18 Nov

The Communal Cycle of Sharing

What I'm interested in this year is how we're continuing to expand on tools, services, and shared side projects to collectively guide where we take the web next, and the way we're sharing that.

So many other mediums—mostly analog ones—have been around for ages and have a deeper history. In the grand scheme of things, the web, and thus the job of building for it, are still pretty new. We talk about open source and licenses, the ebbs and flows … Read article

The post The Communal Cycle of Sharing appeared first on CSS-Tricks.

18 Nov

The Best Cocktail in Town

I admit I've held in a lot of pent-up frustration about the direction web development has taken the past few years. There is the complexity. It requires a steep learning curve. It focuses more on more configuration than it does development.

That's not exactly great news for folks like me who consider themselves to be more on the design side of the front-end spectrum. I remember grimacing the first time I found myself using a Grunt workflow Read article

The post The Best Cocktail in Town appeared first on CSS-Tricks.

18 Nov

The Kind of Development I Like

I'm turning 40 next year (yikes!) and even though I've been making websites for over 25 years, I feel like I'm finally beginning to understand the kind of development I like. Expectedly, these are not new revelations and my views can be summed up by two older Computer Science adages that pre-date my career.

Composition over inheritance Convention over configuration

Allow me to take you on a short journey. In modern component-driven web development, I often end up with or … Read article

The post The Kind of Development I Like appeared first on CSS-Tricks.

18 Nov

We asked web developers we admire: “What about building websites has you interested this year?”

For the first time ever here on CSS-Tricks, we're going to do an end-of-year series of posts. Like an Advent calendar riff, only look at us, we're beating the Advent calendar rush! We'll be publishing several articles a day from a variety of web developers we look up to, where gave them all the same prompt:

What about building websites has you interested this year?

We're aiming for a bit of self-reflection and real honesty. As in, not what … Read article

The post We asked web developers we admire: “What about building websites has you interested this year?” appeared first on CSS-Tricks.

18 Nov

Ways to Organize and Prepare Images for a Blur-Up Effect Using Gatsby

Gatsby does a great job processing and handling images. For example, it helps you save time with image optimization because you don’t have to manually optimize each image on your own.

With plugins and some configuration, you can even setup image preloading and a technique called blur-up for your images using Gatsby. This helps with a smoother user experience that is faster and more appealing.

I found the combination of gatsby-source-filesystem, GraphQL, Sharp plugins and gatsby-image quite tedious … Read article

The post Ways to Organize and Prepare Images for a Blur-Up Effect Using Gatsby appeared first on CSS-Tricks.

18 Nov

Layout Templates and Basic Navigation in Flutter Web

Flutter web layout templates

Today we’ll go over something that’s very common and also very important for web development. Traditionally websites has taken up a large part of the screen. To keep the navigation within a web page less jarring certain parts of the view is kept in tact while the content you’re navigating to is replaced. The most common example of this is the Navigation bar on a website that stays the same even as you’re navigating to “different pages”. I put “different pages” in quotation marks because of the following.

This tutorial will continue from the code produced at the end of part 2. You can download the starting code here.

Implementation

This is how we’ll be breaking up our website UI. For the website I’m building I want the blue section (Navigation bar) to stay exactly the same for every view. When we navigate to a view only the red section (Content) will swap out.

Layout Template

We’ll introduce a new widget called LayoutTemplate. This will be supplied as the root layout of the MaterialApp through the home property. It will contain all the NavigationBar and NavigationDrawer code that we currently have in the HomeView with one addition. The child of the expanded widget will be a navigator which will allow us to replace the content of the Expanded only using the navigation calls. Create a new folder under views called layout_template and inside a new file called layout_template.dart.

class LayoutTemplate extends StatelessWidget {  const LayoutTemplate({Key key}) : super(key: key);
  @override  Widget build(BuildContext context) {    return ResponsiveBuilder(      builder: (context, sizingInformation) => Scaffold(        drawer: sizingInformation.isMobile ? NavigationDrawer() : null,        backgroundColor: Colors.white,        body: CenteredView(          child: Column(            children: <Widget>[              NavigationBar(),              Expanded(                  child: Navigator(),              )            ],          ),        ),      ),    );  }}
Custom navigation

We know based on the design, when a user navigates somewhere we want the NavigationBar and NavigationDrawer UI to stay in place and only content section to swap out. Marked with red in the above image. To achieve that we need to embed a Navigator widget as the child of the Expanded child. I like to setup a NavigationService so I can navigate from my ViewModels (which we'll add in a later episode). Create a new folder called services under lib and inside a new file called navigation_service.dart

class NavigationService {  final GlobalKey<NavigatorState> navigatorKey =      GlobalKey<NavigatorState>();
  Future<dynamic> navigateTo(String routeName) {    return navigatorKey.currentState.pushNamed(routeName);  }
  bool goBack() {    return navigatorKey.currentState.pop();  }}

Quick Dislaimer Keep in mind, when using my Mvvm architecture setup the navigation service will be used in the viewModel and not in the UI. Only the viewModel should execute functions or perform actions that change the state of the navigation service or the app. We CAN still use it to supply a value like a key to the Navigator, but it shouldn’t execute functions that change state. In this tutorial we’ll do that, but that’s because we don’t have the viewmodels and state management setup properly yet.

Setup GetIt

Now that that’s out of the way we can setup get_it for our service location. Add the package to your pubspec

get_it:

Create a new file under the lib folder called locator.dart

import 'package:get_it/get_it.dart';import 'package:the_basics/services/navigation_service.dart';
GetIt locator = GetIt.instance;
void setupLocator() {  locator.registerLazySingleton(() => NavigationService());}

Then make sure to call setupLocator before the app is run. Open up main.dart and update your main function.

void main() {  setupLocator();  runApp(MyApp());}

If the get_it stuff is confusing you can read a short post here that goes over how and why to use it.

Named Routing

I’ve covered navigation in Flutter in depth and today we’ll be using named routing in Flutter. A navigator expects a function that generates a route given a name, IF you’re using named navigation. We’ll create the function that will supply our different routes based on the names. First thing we’ll do is create a new folder called routing under the lib folder. Inside that folder we’ll create a new file called route_names.dart

const String HomeRoute = "home";const String AboutRoute = "about";const String EpisodesRoute = "episodes";

I’m keeping the names of the routes easily identifiable so that I don’t have to import using an alias to make it more readable. In the same routing folder create a new file called router.

Route<dynamic> generateRoute(RouteSettings settings) {  print('generateRoute: ${settings.name}');  switch (settings.name) {    case HomeRoute:      return _getPageRoute(HomeView());    case EpisodesRoute:      return _getPageRoute(EpisodesView());    case AboutRoute:      return _getPageRoute(AboutView());    default:      return _getPageRoute(HomeView());  }}
PageRoute _getPageRoute(Widget child) {  return MaterialPageRoute(    builder: (context) => child,  );}

What we’re doing here is setting up a switch statement to check which view we are requesting through the named navigation and then building and returning that widget within a MaterialPageRoute. Now that it's all setup we can supply the code to our Navigator in the LayoutTemplate.

class LayoutTemplate extends StatelessWidget {  const LayoutTemplate({Key key}) : super(key: key);
  @override  Widget build(BuildContext context) {    return ResponsiveBuilder(      builder: (context, sizingInformation) => Scaffold(              ...              Expanded(                  child: Navigator(                key: locator<NavigationService>().navigatorKey,                onGenerateRoute: generateRoute,                initialRoute: HomeRoute,              ))            ],          ),        ),      ),    );  }}

We set the navigator key to the one we can control from the service. We supply the generateRoute call and set the initialRoute to the HomeRoute. Next up we can update the HomeView file to remove all the code that's now in the LayoutTemplate and then also create two more views. Episodes and About.

class HomeView extends StatelessWidget {  const HomeView({Key key}) : super(key: key);
  @override  Widget build(BuildContext context) {    return ScreenTypeLayout(      mobile: HomeContentMobile(),      desktop: HomeContentDesktop(),    );  }}

Create a new folder under views called episodes and inside a new file called episodes_view.dart

class EpisodesView extends StatelessWidget {  const EpisodesView({Key key}) : super(key: key);
  @override  Widget build(BuildContext context) {    return Center(      child: Text('Episodes View'),    );  }}

Create another folder under views called about, and inside a new file called about_view.dart

class AboutView extends StatelessWidget {  const AboutView({Key key}) : super(key: key);
  @override  Widget build(BuildContext context) {    return Center(      child: Text('About View'),    );  }}

Now we have to perform the actual navigation. This will be done in the NavBarItem where we'll access the NavigationService and navigateTo. You shouldn't be doing this directly from the UI, but we won't be covering the ViewModel setup in this article so we have to do it the bad way.

We’ll update the navbar_item. We’ll wrap the Text in a GestureDetector then call navigateTo onTap. We'll also pass in an additional value which will be the navigationPath.

class NavBarItem extends StatelessWidget {  final String title;  final String navigationPath;  const NavBarItem(this.title, this.navigationPath);
  @override  Widget build(BuildContext context) {    return GestureDetector(      onTap: () {        locator<NavigationService>().navigateTo(navigationPath);      },      child: Text(        title,        style: TextStyle(fontSize: 18),      ),    );  }}

Then we have to go through the code and update every where the NavBarItem is being used. Go to navigation_bar_tablet_desktop.dart and pass in the correct route for the items.

...NavBarItem('Episodes', EpisodesRoute),SizedBox(  width: 60,),NavBarItem('About', AboutRoute),...

Go to the DrawerItem and update the constructor to take in a new String, navigationPath and pass that to the NavBarItem. It should probably be one widget that changes it's layout based on the screen type. You can do that as an exercise. Combine the NavBarItem and the DrawerItem into a single responsive widget.

class DrawerItem extends StatelessWidget {  final String title;  final IconData icon;  final String navigationPath;  const DrawerItem(this.title, this.icon, this.navigationPath);
  @override  Widget build(BuildContext context) {    return Padding(      padding: const EdgeInsets.only(left: 30, top: 60),      child: Row(        children: <Widget>[          Icon(icon),          SizedBox(            width: 30,          ),          NavBarItem(title, navigationPath)        ],      ),    );  }}

Then head to the navigation_drawer and update the DrawerItem's to take in the correct paths.

...child: Column(  children: <Widget>[    NavigationDrawerHeader(),    DrawerItem('Episodes', Icons.videocam, EpisodesRoute),    DrawerItem('About', Icons.help, AboutRoute),  ],),...

Run the code now and you’ll have a website where you can navigate keeping the nav bar constant and just swapping out the content section. Pretty legit, that code will all be rolled up into a package in time so it’ll go much faster. If you run the code now and click on Episodes or About you’ll see the content swap out with the default MaterialPage transition. One last thing I'd like to do is make it fade instead. Open the router.dart file, add the _FadeRoute class at the bottom of it and update the _getPageRoute function.

PageRoute _getPageRoute(Widget child) {  return _FadeRoute(    child: child,  );}
class _FadeRoute extends PageRouteBuilder {  final Widget child;  _FadeRoute({this.child})      : super(          pageBuilder: (            BuildContext context,            Animation<double> animation,            Animation<double> secondaryAnimation,          ) =>              child,          transitionsBuilder: (            BuildContext context,            Animation<double> animation,            Animation<double> secondaryAnimation,            Widget child,          ) =>              FadeTransition(            opacity: animation,            child: child,          ),        );}

Now if you run the code the pages that you navigate to fade in and out. I don’t know how to match the url path in the browser with a custom nested navigator. As I explore I’ll probably figure that out. For now that’s it for the navigation. Using this you should be able to build a basic web app (without direct url navigation).

If you’re enjoying this series then follow me on Youtube where I release the episodes first before my written blog post.

Flutter Community

Layout Templates and Basic Navigation in Flutter Web was originally published in Flutter Community on Medium, where people are continuing the conversation by highlighting and responding to this story.

18 Nov

The Department of Useless Images

Gerry McGovern:

The Web is smothering in useless images. These clichéd, stock images communicate absolutely nothing of value, interest or use. They are one of the worst forms of digital pollution because they take up space on the page, forcing more useful content out of sight. They also slow down the site’s ability to download quickly.

:laugh: :cry:

It's so true, isn't it? How much bandwidth and electricity is spent sending middle-aged-man-staring-into-camera.jpg?

Great photography can be a powerful emotional … Read article

The post The Department of Useless Images appeared first on CSS-Tricks.

18 Nov

Abstracting WordPress Code To Reuse With Other CMSs: Concepts (Part 1)

Making code that is agnostic of the CMS or framework has several benefits. For instance, through its new content editor Gutenberg, WordPress enables to code components which can be used for other CMSs and frameworks too, such as for Drupal and for Laravel. However, Gutenberg’s emphasis on re-utilization of code is focused on the client-side code of the component (JavaScript and CSS); concerning the component’s backend code (such as the provision of APIs that feed data to the component) there is no pre-established consideration.