emGee Software Solutions Custom Database Applications

Share this

Web Technologies

Typescript-ExpressJS MVC pattern

Echo JS - Thu, 05/16/2019 - 12:15
Categories: Web Technologies

Vue and Vue-Testing-Library

Echo JS - Thu, 05/16/2019 - 12:15
Categories: Web Technologies

Iterating a React Design with Styled Components

CSS-Tricks - Thu, 05/16/2019 - 07:29

In a perfect world, our projects would have unlimited resources and time. Our teams would begin coding with well thought out and highly refined UX designs. There would be consensus among developers about the best way to approach styling. There’d be one or more CSS gurus on the team who could ensure that functionality and style could roll out simultaneously without it turning into a train-wreck.

I’ve actually seen this happen in large enterprise environments. It’s a beautiful thing. This article is not for those people.

On the flip side of the coin is the tiny startup that has zero funding, one or two front-end developers, and a very short timeline to demonstrate some functionality. It doesn’t have to look perfect, but it should at least render reasonably well on desktop, tablet, and mobile. This gets them to a point where it can be shown to advisors and early users; maybe even potential investors who’ve expressed an interest in the concept. Once they get some cashflow from sales and/or investment, they can get a dedicated UX designer and polish the interface.

What follows is for this latter group.

Project Kickoff Meeting

Let’s invent a company to get the ball rolling.

Solar Excursions is a small travel agency aiming to serve the near-future’s burgeoning space tourism industry.

Our tiny development team has agreed that React will be used for the UI. One of our front-end developers is big on Sass, and the other is enamored with CSS in JavaScript. But they’ll be hard pressed to knock out their initial sprint goals; there’s certainly no time for arguing about the best possible styling approach. Both coders agree the choice doesn’t matter much in the long run, as long as its consistently executed. They’re certain that implementing the styling from scratch under the gun now will incur technical debt that will have to be cleaned up later.

After some discussion, the team opts to plan for one or more "styling refactor" sprints. For now, we’ll just focus on getting something up on the screen using React-Bootstrap. That way we’ll be able to quickly build working desktop and mobile layouts without much fuss.

The less time spent on front-end styling the better, because we’ll also need the UI to hook up to the services our backend developer will be cranking out. And, as our application architecture begins to take shape, both front-enders agree it’s important that it be unit tested. They have a lot on their plate.

Based on my discussions with the Powers That Be, as a dedicated project manager, I slaved over Balsamiq for at least ten minutes to provide the team with mockups for the booking page on desktop and mobile. I assume they’ll make tablet meet in the middle and look reasonable.

Initial mockups for the Solar Excursions Trip Booking Page on desktop (left) and mobile (right). Sprint Zero: Review Meeting

Pizza all around! The team worked really hard to hit its goals, and we now have a booking page with a layout that approximates the mockups. The infrastructure for services is coming together, but there’s quite a way to go before we can connect the UI to it. In the interim, the front-enders are using a hardcoded mock data structure.

The first iteration of the page in code using react-bootstrap.

Here’s a look at our UI code so far:

This is all straightforward React. We’re using some of that Hooks hotness, but it’s probably passé to most of you by now.

The key takeaway to notice here is how four of our five application components import and use components from react-bootstrap. Only the main App component is unaffected. That’s because it just composes the top level view with our custom components.

// App.js imports import React, { useState } from "react"; import Navigation from "./Navigation"; import Page from "./Page"; // Navigation.js imports import React from "react"; import { Navbar, Dropdown, Nav } from "react-bootstrap"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { Container, Row, Col } from "react-bootstrap"; // PosterCarousel.js imports import React from "react"; import { Alert, Carousel, Image } from "react-bootstrap"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { Button, Card, Col, Container, Dropdown, Jumbotron, ListGroup, Row, ToggleButtonGroup, ToggleButton } from "react-bootstrap";

The decision to move fast with Bootstrap has allowed us to hit our sprint goals, but we’re already accumulating technical debt. This is just four affected components, but as the application grows, it’s clear the "styling refactor" sprints that we planned for are going to become exponentially harder. And we haven’t even customized these components much. Once we have tens of components, all using Bootstrap with lots of inline styling to pretty them up, refactoring them to remove react-bootstrap dependencies will be a scary proposition indeed.

Rather than building more of the booking pipeline pages, the team decides that we’ll spend the next sprint working to isolate the react-bootstrap usage in a custom component kit since our services are still under construction. Application components will only use components from this kit. That way, when it comes time to ween ourselves from react-bootstrap, the process will be much easier. We won’t have to refactor thirty usages of the react-bootstrap Button throughout the app, we’ll just rewrite the internals of our KitButton component.

Sprint One: Review Meeting

Well, that was easy. High-fives. No change to the visual appearance of the UI, but we now have a "kit" folder that’s sibling to "components" in our React source. It has a bunch of files like KitButton.js, which basically export renamed react-bootstrap components.

An example component from our kit looks like this:

// KitButton.js import { Button, ToggleButton, ToggleButtonGroup } from "react-bootstrap"; export const KitButton = Button; export const KitToggleButton = ToggleButton; export const KitToggleButtonGroup = ToggleButtonGroup;

We wrap those all kit components up into a module like this:

// kit/index.js import { KitCard } from "./KitCard"; import { KitHero } from "./KitHero"; import { KitList } from "./KitList"; import { KitImage } from "./KitImage"; import { KitCarousel } from "./KitCarousel"; import { KitDropdown } from "./KitDropdown"; import { KitAttribution } from "./KitAttribution"; import { KitNavbar, KitNav } from "./KitNavbar"; import { KitContainer, KitRow, KitCol } from "./KitContainer"; import { KitButton, KitToggleButton, KitToggleButtonGroup } from "./KitButton"; export { KitCard, KitHero, KitList, KitImage, KitCarousel, KitDropdown, KitAttribution, KitButton, KitToggleButton, KitToggleButtonGroup, KitContainer, KitRow, KitCol, KitNavbar, KitNav };

And now our application components are completely free of react-bootstrap. Here are the imports for the affected components:

// Navigation.js imports import React from "react"; import { KitNavbar, KitNav, KitDropdown } from "../kit"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { KitContainer, KitRow, KitCol } from "../kit"; // PosterCarousel.js imports import React from "react"; import { KitAttribution, KitImage, KitCarousel } from "../kit"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { KitCard, KitHero, KitList, KitButton, KitToggleButton, KitToggleButtonGroup, KitDropdown, KitContainer, KitRow, KitCol } from "../kit";

Here’s the front-end codebase now:

Although we’ve corralled all of the react imports into our kit components, our application components still rely a bit on the react-bootstrap implementation because the attributes we place on our kit component instances are the same as those of react-bootstrap. That constrains us when it comes to re-implementing the kit components, because we need to adhere to the same API. For instance:

// From Navigation.js <KitNavbar bg="dark" variant="dark" fixed="top">

Ideally, we wouldn’t have to add those react-bootstrap specific attributes when we instantiate our KitNavbar.

The front-enders promise to refactor those out as we go, now that we’ve identified them as problematic. And any new references to react-bootstrap components will go into our kit instead of directly into the application components.

Meanwhile, we’ve shared our mock data with the server engineer, who is working hard to build separate server environments, implement the database schema, and expose some services to us.

That gives us time to add some gloss to our UI in the next sprint — which is good because the Powers That Be would like to see separate themes for each destination. As the user browses destinations, we need to have the UI color scheme change to match the displayed travel poster. Also, we want to try and spiff up those components a bit to begin evolving our own look and feel. Once we have some money coming in, we’ll get a designer to do a complete overhaul, but hopefully we can reach a happy medium for our early users.

Sprint Two: Review Meeting

Wow! The team really pulled out all the stops this sprint. We got per-destination themes, customized components, and a lot of the lingering react-bootstrap API implementations removed from the application components.

Here’s what the desktop looks like now:

Check out the solarized theme for the red planet!

In order to pull this off, the front-enders brought in the Styled Components library. It made styling the individual kit components a breeze, as well as adding support for multiple themes.

Let’s look at a few highlights of their changes for this sprint.

First, for global things like pulling in fonts and setting the page body styles, we have a new kit component called KitGlobal.

// KitGlobal.js import { createGlobalStyle } from "styled-components"; export const KitGlobal = createGlobalStyle` body { @import url('https://fonts.googleapis.com/css?family=Orbitron:500|Nunito:600|Alegreya+Sans+SC:700'); background-color: ${props => props.theme.foreground}; overflow-x: hidden; } `;

It uses the createGlobalStyle helper to define the CSS for the body element. That imports our desired web fonts from Google, sets the background color to whatever the current theme’s "foreground" value is, and turns off overflow in the x-direction to eliminate a pesky horizontal scrollbar. We use that KitGlobal component in the render method of our App component.

Also in the App component, we import ThemeProvider from styled-components, and something called "themes" from ../theme. We use React’s useState to set the initial theme to themes.luna and React’s useEffect to call setTheme whenever the "destination" changes. The returned component is now wrapped in ThemeProvider, which is passed "theme" as a prop. Here’s the App component in its entirety.

// App.js import React, { useState, useEffect } from "react"; import { ThemeProvider } from "styled-components"; import themes from "../theme/"; import { KitGlobal } from "../kit"; import Navigation from "./Navigation"; import Page from "./Page"; export default function App(props) { const [destinationIndex, setDestinationIndex] = useState(0); const [theme, setTheme] = useState(themes.luna); const destination = props.destinations[destinationIndex]; useEffect(() => { setTheme(themes[destination.theme]); }, [destination]); return ( <ThemeProvider theme={theme}> <React.Fragment> <KitGlobal /> <Navigation {...props} destinationIndex={destinationIndex} setDestinationIndex={setDestinationIndex} /> <Page {...props} destinationIndex={destinationIndex} setDestinationIndex={setDestinationIndex} /> </React.Fragment> </ThemeProvider> ); }

KitGlobal is rendering like any other component. Nothing special there, only that the body tag is affected. ThemeProvider is using the React Context API to pass theme down to whatever components need it (which is all of them). In order to fully understand that, we also need to take a look at what a theme actually is.

To create a theme, one of our front-enders took all the travel posters and created palettes for each by extracting the prominent colors. That was fairly simple.

We used TinyEye for this.

Obviously, we weren’t going to use all the colors. The approach was mainly to dub the most used two colors foreground and background. Then we took three more colors, generally ordered from lightest to darkest as accent1, accent2, and accent3. Finally, we picked two contrasting colors to call text1 and text2. For the above destination, that looked like:

// theme/index.js (partial list) const themes = { ... mars: { background: "#a53237", foreground: "#f66f40", accent1: "#f8986d", accent2: "#9c4952", accent3: "#f66f40", text1: "#f5e5e1", text2: "#354f55" }, ... }; export default themes;

Once we have a theme for each destination, and it is being passed into all the components (including the kit components that our application components are now built from), we need to use styled-components to apply those theme colors as well as our custom visual styling, like the panel corners and "border glow."

This is a simple example where we made our KitHero component apply the theme and custom styles to the Bootstrap Jumbotron:

// KitHero.js import styled from "styled-components"; import { Jumbotron } from "react-bootstrap"; export const KitHero = styled(Jumbotron)` background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Nunito", sans-serif; margin-bottom: 20px; `;

In this case, we’re good to go with what gets returned from styled-components, so we just name it KitHero and export it.

When we use it in the application, it looks like this:

// DestinationLayout.js (partial code) const renderHero = () => { return ( <KitHero> <h2>{destination.header}</h2> <p>{destination.blurb}</p> <KitButton>Book Your Trip Now!</KitButton> </KitHero> ); };

Then there are more complex cases where we want to preset some attributes on the react-bootstrap component. For instance, the KitNavbar component which we identified earlier as having a bunch of react-bootstrap attributes that we’d rather not pass from the application’s declaration of the component.

Now for a look at how that was handled:

// KitNavbar.js (partial code) import React, { Component } from "react"; import styled from "styled-components"; import { Navbar } from "react-bootstrap"; const StyledBootstrapNavbar = styled(Navbar)` background-color: ${props => props.theme.background}; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; display: flex; flex-direction: horizontal; justify-content: space-between; font-family: "Nunito", sans-serif; `; export class KitNavbar extends Component { render() { const { ...props } = this.props; return <StyledBootstrapNavbar fixed="top" {...props} />; } }

First, we create a component called StyledBootstrapNavbar using styled-components. We were able to handle some of the attributes with the CSS we passed to styled-components. But in order to continue leveraging (for now) the reliable stickiness of the component to the top of the screen while everything else is scrolled, our front-enders elected to continue using react-bootstrap’s fixed attribute. In order to do that, we had to create a KitNavbar component that rendered an instance of StyledBootstrapNavbar with the fixed=top attribute. We also passed through all the props, which includes its children.

We only have to create a separate class that renders styled-component’s work and passes props through to it if we want to explicitly set some attributes in our kit component by default. In most cases, we can just name and return styled-component’s output and use it as we did with KitHero above.

Now, when we render the KitNavbar in our application’s Navigation component, it looks like this:

// Navigation.js (partial code) return ( <KitNavbar> <KitNavbarBrand> <KitLogo /> Solar Excursions </KitNavbarBrand> {renderDestinationMenu()} </KitNavbar> );

Finally, we took our first stabs at refactoring our kit components away from react-bootstrap. The KitAttribution component is a Bootstrap Alert which, for our purposes, is little more than an ordinary div. We were able to easily refactor to remove its dependency on react-bootstrap.

This is the component as it emerged from the previous sprint:

// KitAttribution.js (using react-bootstrap) import { Alert } from "react-bootstrap"; export const KitAttribution = Alert;

This is what it looks like now:

// KitAttribution.js import styled from "styled-components"; export const KitAttribution = styled.div` text-align: center; background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Alegreya Sans SC", sans-serif; > a { color: ${props => props.theme.text2}; font-family: "Nunito", sans-serif; } > a:hover { color: ${props => props.theme.background}; text-decoration-color: ${props => props.theme.accent3}; } `;

Notice how we no longer import react-bootstrap and we use styled.div as the component base. They won’t all be so easy, but it’s a process.

Here are the results of our team’s styling and theming efforts in sprint 3:

Conclusion

After three sprints, our team is well on its way to having a scalable component architecture in place for the UI.

  • We are moving quickly thanks to react-bootstrap, but are no longer piling up loads of technical debt as a result of it.
  • Thanks to styled-components, we were able to implement multiple themes (like how almost every app on the Internet these days sports dark and light modes). We also don’t look like an out-of-the-box Bootstrap app anymore.
  • By implementing a custom component kit that contains all references to react-bootstrap, we can refactor away from it as time permits.

The post Iterating a React Design with Styled Components appeared first on CSS-Tricks.

Categories: Web Technologies

Evergreen Googlebot

CSS-Tricks - Thu, 05/16/2019 - 07:28

I've heard people say that the #1 most exciting and important thing that came out of Google I/O this year was the evergreen Googlebot:

Today, we are happy to announce that Googlebot now runs the latest Chromium rendering engine (74 at the time of this post) when rendering pages for Search. Moving forward, Googlebot will regularly update its rendering engine to ensure support for latest web platform features.

Before this, I guess I never even thought about it.

I guess part of it is that some people did already know that the old version didn't support some newfangled JavaScript stuff, and thus literally packaged their app with old JavaScript to be more SEO-friendly.

A bunch of people were apparently shipping older code simply for the sake of Googlebot, and now they don't have to. Sure, I'll call that a win.

Don't read this news as "don't worry about your JavaScript-rendered pages and SEO" though, because Google Webmasters is still telling us that pages with content that requires JavaScript to render are put into a special slower queue for both initial crawling and for updates. Not necessarily a penalty, but certainly a delay. I'm sure that's enough to make server-side rendering a priority for sites where SEO is the whole ballgame.

Direct Link to ArticlePermalink

The post Evergreen Googlebot appeared first on CSS-Tricks.

Categories: Web Technologies

Using Jetpack to Accelerate WordPress Development

CSS-Tricks - Thu, 05/16/2019 - 07:25

(This is a sponsored post.)

[Geoff:] I've built a fair number of WordPress sites in my day. It's been my go-to since the 2.x-ish days because it works for any site, big or small. That's the sort of solution and flexibility you like to have as a freelancer.

Boy, I wish I had Jetpack available in those early days.

Like WordPress itself, Jetpack is a good solution for many, many of the types of things clients are looking for from a WordPress site. I used to spend hours researching the right plugin for a specific feature, whether that was for comment filtering, asset caching, beefier search functionality, creating custom post types on the fly... you name it. All of that — and a heckuva lot more — is included in Jetpack right out of the box.

Here's what I'm talking about. A friend of mine runs a pop-up gallery here locally. She displays paintings, photographs, sculptures... basically anything super artsy from super talented locals. That includes events, socials, performances and screenings. The wild thing is that it "pops" up in different spots, based on what she's showing and what public space is available. So, you get how a website would be helpful for visitors to keep tabs on what's coming up and where things are going to take place, not to mention getting a recap on past events.

We've all made sites for friends, right? It's the kind of thing you do for free on the side. That makes it something you want to do well, but not necessarily spend a ton of time making. That's where Jetpack really helped me out in this case.

If Jetpack is new to you, it's a WordPress plugin that, as part of what it does, is bring features from WordPress.com and makes them available on your self-hosted WordPress sites.

For example, my friend really needed to showcase work. This is less of a content site and more of a visual experience, so media plays a big role. Photos, video, audio. You get it. Good thing Jetpack has a "Portfolio" custom post type at the ready.

That's a perfect start for showing things off, but my friend also needed a carousel to allow visitors to browse photos from events and artist works. This would've been something I probably would have turned to the WordPress plugin directory for in the past, or perhaps some (back then) jQuery plugin, but thankfully Jetpack had my back there, too.

While we're on the topic of media, we know that heavy image files are a recipe for slow sites. There's a ton of WordPress plugins that can help with caching, gzipping, and even lazy loading, but all that's already in Jetpack. Why go reinvent the wheel, especially on what's supposed to be a pretty quick build?

I think you catch my drift. The fact is that Jetpack is an effective way to supercharge a self-hosted WordPress site, connecting it to many of the same powerful services that you'd otherwise need to go to WordPress.com — or gobs of third-party plugins — to get. Plus, it's built by Automattic, so you know it integrates seamlessly with WordPress. No better confidence than going with something the primary maintainers of WordPress are willing to slap their name on!

Sure, we've only looked at a very simple example of how powerful Jetpack is for a small site. But don't be fooled: Jetpack is capable of handling the needs of large-scale sites as well. In fact, we love Jetpack here at CSS-Tricks because it powers so much of what you see on the site, from social sign-in and automated sharing, to downtime monitoring and site search. It's robust, dependable, and just gosh darn delightful to use.

And, hey, there's a free tier you can start using right away and it includes a generous number of features that help with security, performance, analytics, and theming... and it only goes up from there. &#x1f680;

Get Jetpack

Direct Link to ArticlePermalink

The post Using Jetpack to Accelerate WordPress Development appeared first on CSS-Tricks.

Categories: Web Technologies

JavaScript tutorial: Beyond basic charts with React-vis

InfoWorld JavaScript - Thu, 05/16/2019 - 03:00

Last week we took a first look at React-vis, the open-source charting library, and built up our first bar chart using the City of New York Popular Baby Names data set. This week, we’ll expand on our initial example and show how we can begin to incorporate basic interactions. As a refresher, our data set includes rows of data that look like this:

To read this article in full, please click here

(Insider Story)
Categories: Web Technologies

MySQL Router 8.0.16: What’s new

MySQL Server Blog - Thu, 05/16/2019 - 02:13
MySQL Router 8.0.16 Key features
  • log-rotation via SIGHUP
  • HTTP server plugin
  • flexible support for single/multi-PRIMARY Group Replication
Logrotation via SIGHUP

Sending a SIGHUP signal to the router process will now close and reopen the logfile.

It allows the integration with the logrotate to rotate and compress the Router’s logfiles.…

Facebook Twitter Google+ LinkedIn
Categories: Web Technologies

Remove unused "use" imports in PHP - Christian Weiske

Planet PHP - Wed, 05/15/2019 - 12:09

To clean up unused namespace imports (use statements) in many PHP files at once, php-cs-fixer (version 2) is of great help:

$ php php-cs-fixer.phar fix --rules=no_unused_imports src/
Categories: Web Technologies

A Deep Dive into Native Lazy-Loading for Images and Frames

CSS-Tricks - Wed, 05/15/2019 - 08:04

Today's websites are packed with heavy media assets like images and videos. Images make up around 50% of an average website's traffic. Many of them, however, are never shown to a user because they're placed way below the fold.

What’s this thing about images being lazy, you ask? Lazy-loading is something that’s been covered quite a bit here on CSS-Tricks, including a thorough guide with documentation for different approaches using JavaScript. In short, we’re talking about a mechanism that defers the network traffic necessary to load content when it’s needed — or rather when trigger the load when the content enters the viewport.

The benefit? A smaller initial page that loads faster and saves network requests for items that may not be needed if the user never gets there.

If you read through other lazy-loading guides on this or other sites, you’ll see that we’ve had to resort to different tactics to make lazy-loading work. Well, that’s about to change when lazy-loading will be available natively in HTML as a new loading attribute… at least in Chrome which will hopefully lead to wider adoption. Chrome has already merged the code for native lazy-loading and is expected to ship it in Chrome 75, which is slated to release June 4, 2019.

The pre-native approach

Until now, developers like ourselves have had to use JavaScript (whether it’s a library or something written from scratch) in order to achieve lazy-loading. Most libraries work like this:

  • The initial, server-side HTML response includes an img element without the src attribute so the browser does not load any data. Instead, the image's URL is set as another attribute in the element's data set, e. g. data-src.
  • <img data-src="https://tiny.pictures/example1.jpg" alt="...">
  • Then, a lazy-loading library is loaded and executed.
  • <script src="LazyLoadingLibrary.js"></script> <script>LazyLoadingLibrary.run()</script>
  • That keeps track of the user's scrolling behavior and tells the browser to load the image when it is about to be scrolled into view. It does that by copying the data-src attribute's value to the previously empty src attribute.
  • <img src="https://tiny.pictures/example1.jpg" data-src="https://tiny.pictures/example1.jpg" alt="...">

This has worked for a pretty long time now and gets the job done. But it’s not ideal for good reasons.

The obvious problem with this approach is the length of the critical path for displaying the website. It consists of three steps, which have to be carried out in sequence (after each other):

  1. Load the initial HTML response
  2. Load the lazy-loading library
  3. Load the image file

If this technique is used for images above the fold the website will flicker during loading because it is first painted without the image (after step 1 or 2, depending on if the script uses defer or async) and then — after having been loaded — include the image. It will also be perceived as loading slowly.

In addition, the lazy-loading library itself puts an extra weight on the website's bandwidth and CPU requirements. And let’s not forget that a JavaScript approach won't work for people who have JavaScript disabled (although we shouldn't really care about them in 2019, should we?).

Oh, and what about sites that rely on RSS to distribute content, like CSS-Tricks? The initial image-less render means there are no images in the RSS version of content as well.

And so on.

Native lazy-loading to the rescue!

As we noted at the start, Chromium and Google Chrome will ship a native lazy-loading mechanism in the form of a new loading attribute, starting in Chrome 75. We’ll go over the attribute and its values in just a bit, but let’s first get it working in our browsers so we can check it out together.

Enable native lazy-loading

Until Chrome 75 is officially released, we have Chrome Canary and can enable lazy-loading manually by switching two flags.

  1. Open chrome://flags in Chromium or Chrome Canary.
  2. Search for lazy.
  3. Enable both the "Enable lazy image loading" and the "Enable lazy frame loading" flag.
  4. Restart the browser with the button in the lower right corner of the screen.
Native lazy-loading flags in Google Chrome

You can check if the feature is properly enabled by opening your JavaScript console (F12). You should see the following warning:

[Intervention] Images loaded lazily and replaced with placeholders. Load events are deferred."

All set? Now we get to dig into the loading attribute.

The loading attribute

Both the img and the iframe elements will accept the loading attribute. It's important to note that its values will not be taken as a strict order by the browser but rather as a hint to help the browser make its own decision whether or not to load the image or frame lazily.

The attribute can have three values which are explained below. Next to the images, you'll find tables listing your individual resource loading timings for this page load. Range response refers to a kind of partial pre-flight request made to determine the image's dimensions (see How it works) for details). If this column is filled, the browser made a successful range request.

Please note the startTime column, which states the time image loading was deferred after the DOM had been parsed. You might have to perform a hard reload (CTRL + Shift + R) to re-trigger range requests.

The auto (or unset) value <img src="auto-cat.jpg" loading="auto" alt="..."> <img src="auto-cat.jpg" alt="..."> <iframe src="https://css-tricks.com/" loading="auto"></iframe> <iframe src="https://css-tricks.com/"></iframe> Auto cat loaded automatically

Setting the loading attribute to auto (or simply leaving the value blank, as in loading="") lets the browser decide whether or not to lazy-load an image. It takes many things into consideration to make that decision, like the platform, whether Data Saver mode is enabled, network conditions, image size, image vs. iframe, the CSS display property, among others. (See How it works) for info about why all this is important.)

The eager value <img src="auto-cat.jpg" loading="eager" alt="..."> <iframe src="https://css-tricks.com/" loading="eager"></iframe> Eager cat loaded eagerly

The eager value provides a hint to the browser that an image should be loaded immediately. If loading was already deferred (e. g. because it had been set to lazy and was then changed to eager by JavaScript), the browser should start loading the image immediately.

The lazy value <img src="auto-cat.jpg" loading="lazy" alt="..."> <iframe src="https://css-tricks.com/" loading="lazy"></iframe> Lazy cat loaded lazily

The lazy value provides a hints to the browser that an image should be lazy-loaded. It's up to the browser to interpret what exactly this means, but the explainer document states that it should start loading when the user scrolls "near" the image such that it is probably loaded once it actually comes into view.

How the loading attribute works

In contrast to JavaScript lazy-loading libraries, native lazy-loading uses a kind of pre-flight request to get the first 2048 bytes of the image file. Using these, the browser tries to determine the image's dimensions in order to insert an invisible placeholder for the full image and prevent content from jumping during loading.

The image's load event is fired as soon as the full image is loaded, be it after the first request (for images smaller than 2 KB) or after the second one. Please note that the load event may never be fired for certain images because the second request is never made.

In the future, browsers might make twice as many image requests as there would be under the current proposal. First the range request, then the full request. Make sure your servers support the HTTP Range: 0-2047 header and respond with status code 206 (Partial Content) to prevent them from delivering the full image twice.

Due to the higher number of subsequent requests made by the same user, web server support for the HTTP/2 protocol will become more important.

Let’s talk about deferred content. Chrome's rendering engine Blink uses heuristics to determine which content should be deferred and for how long to defer it. You can find a comprehensive list of requirements in Scott Little's design documentation. This is a short breakdown of what will be deferred:

  • Images and frames on all platforms which have loading="lazy" set
  • Images on Chrome for Android with Data Saver enabled and that satisfy all of the following:
    • loading="auto" or unset
    • no width and height attributes smaller than 10px
    • not created programmatically in JavaScript
  • Frames which satisfy all of the following:
    • loading="auto" or unset
    • is from a third-party (different domain or protocol than the embedding page)
    • larger than 4 pixels in height and width (to prevent deferring tiny tracking frames)
    • not marked as display: none or visibility: hidden (again, to prevent deferring tracking frames)
    • not positioned off-screen using negative x or y coordinates
Responsive images with srcset

Native lazy-loading also works with responsive img elements using the srcset attribute. This attribute offers a list of image file candidates to the browser. Based on the user's screen size, display pixel ratio, network conditions, etc., the browser will choose the optimal image candidate for the occasion. Image optimization CDNs like tiny.pictures are able to provide all image candidates in real-time without any back end development necessary.

<img src="https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg" srcset="https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg?width=400 400w, https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg?width=800 800w" loading="lazy" alt="..."> Browser support

At the time of this writing, no browser supports native-loading by default. However, Chrome will enable the feature, as we’ve covered, starting in Chrome 75. No other browser vendor has announced support so far. (Edge being a kind of exception because it will soon make the switch to Chromium.)

You can detect the feature with a few lines of JavaScript:

if ("loading" in HTMLImageElement.prototype) { // Support. } else { // No support. You might want to dynamically import a lazy-loading library here (see below). }

See the Pen
Native lazy-loading browser support
by Erk Struwe (@erkstruwe)
on CodePen.

Automatic fallback to JavaScript solution with low-quality image placeholder

One very cool feature of most JavaScript-based lazy-loading libraries is the low-quality image placeholder (LQIP). Basically, it leverages the idea that browsers load (or perhaps I should say used to load) the src of an img element immediately, even if it gets later replaced by another URL. This way, it’s possible to load a tiny file size, low-quality image file on page load and later replace it with a full-sized version.

We can now use this to mimic the native lazy-loading’s 2 KB range requests in browsers that do not support this feature in order to achieve the same result, namely a placeholder with the actual image dimensions and a tiny file size.

See the Pen
Native lazy-loading with JavaScript library fallback and low-quality image placeholder
by Erk Struwe (@erkstruwe)
on CodePen.

Conclusion

I'm really excited about this feature. And frankly, I'm still wondering why it hasn't got much more attention until now, given the fact that its release is imminent and the impact on global internet traffic will be remarkable, even if only small parts of the heuristics are changed.

Think about it: After a gradual roll-out for the different Chrome platforms and with auto being the default setting, the world's most popular browser will soon lazy-load below-the-fold images and frames by default. Not only will the traffic amount of many badly-written websites drop significantly, but web servers will be hammered with tiny requests for image dimension detection.

And then there's tracking: Assuming many unsuspecting tracking pixels and frames will be prevented from being loaded, the analytics and affiliate industry will have to act. We can only hope they don't panic and add loading="eager" to every single image, rendering this great feature useless for their users. They should rather change their code to be recognized as tracking pixels by the heuristics described above.

Web developers, analytics and operations managers should check their website's behavior with this feature and their servers' support for Range requests and HTTP/2 immediately.

Image optimization CDNs could help out in case there are any issues to be expected or if you’d like to take image delivery optimization to the max (including automatic WebP support, low-quality image placeholders, and much more). Read more about tiny.pictures!

References

The post A Deep Dive into Native Lazy-Loading for Images and Frames appeared first on CSS-Tricks.

Categories: Web Technologies

A Better Approach for Using Purgecss with Tailwind

CSS-Tricks - Wed, 05/15/2019 - 07:29

Greg Kohn looks at how to use Purgecss — a tool that helps remove unused styles — and Tailwind — a utility-based CSS framework — and why we might want to pair these tools together:

Tailwind, by intention, is aiming to equip you with an arsenal of utility classes by generating more than you need. There are some best practices which will help keep this overall build size down, like limiting your colors and breakpoints or turning off the modules by default before adding them as necessary. Still, you’ll inevitably generate classes that go unused. And honestly, approaching your configuration with an unrelenting miserly attitude will slow you down and make development less fun. By leaning on Purgecss, there’s no worry that the CSS your users download will only include classes that are ultimately needed.

I’ve never used Tailwind or Purgecss, but I reckon the latter could be particularly useful if you have a giant old codebase and you don’t have the resources to refactor things just yet. I guess my only concern with introducing a tool like that is it could encourage folks to not refactor large and problematic areas in their styles – taking the safest route with this tool instead.

For more info about Tailwind, though, Ben Tinsley wrote a great post a while back about how to get started and Nick Basile showed us how to style a form with Tailwind.

Direct Link to ArticlePermalink

The post A Better Approach for Using Purgecss with Tailwind appeared first on CSS-Tricks.

Categories: Web Technologies

My Bref Makefile - Rob Allen

Planet PHP - Wed, 05/15/2019 - 03:02

In order to use Bref efficiently, I've developed a Makefile so that I don't have to remember all the various commands required. In particular, looking up the correct parameters to sam package & sam deploy is a pain and it's much easier to type make deploy and it all works as I expect.

It looks like this:

Makefile:

# vim: noexpandtab tabstop=4 filetype=make .PHONY: list invoke invoke-local deploy outputs lastlog clean clean-all setup REGION := eu-west-2 PROJECT_NAME := hello-world UNIQUE_KEY := 1557903576 BUCKET_NAME := $(PROJECT_NAME)-$(UNIQUE_KEY)-brefapp STACK_NAME := $(PROJECT_NAME)-$(UNIQUE_KEY)-brefapp # default function to invoke. To override: make invoke FUNCTION=foo FUNCTION ?= my-function list: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' invoke: vendor/bin/bref --region=$(REGION) invoke $(FUNCTION) invoke-local: sam local invoke $(FUNCTION) --no-event deploy: sam package \ --region $(REGION) \ --template-file template.yaml \ --output-template-file .stack-template.yaml \ --s3-bucket $(BUCKET_NAME) -sam deploy \ --region $(REGION) \ --template-file .stack-template.yaml \ --stack-name $(STACK_NAME) \ --capabilities CAPABILITY_IAM vendor/bin/bref deployment --region $(REGION) $(STACK_NAME) outputs: aws --region $(REGION) cloudformation describe-stacks --stack-name $(STACK_NAME) | jq '.Stacks[0]["Outputs"]' lastlog: sam logs --region $(REGION) --name $(FUNCTION) geterror: vendor/bin/bref deployment --region $(REGION) $(STACK_NAME) clean: aws --region $(REGION) cloudformation delete-stack --stack-name $(STACK_NAME) clean-all: clean aws --region $(REGION) s3 rb s3://$(BUCKET_NAME) --force setup: aws --region $(REGION) s3 mb s3://$(BUCKET_NAME)

There's three variables that I need to set at the top:

  • REGION – The AWS region. This has to match the Bref layer used in template.yaml.
  • PROJECT_NAME – The name of the project. This is used as part of the S3 bucket and CloudFormation stack names
  • UNIQUE_KEY – A random string to ensure uniqueness for bucket and stack names. I tend to use the current time to the ms, but any string.

I've included a full-cycle set of targets so make setup will create the initial S3 bucket that's required for the project and then make deploy is used to deploy my project.

If I want to start again, make clean will remove the CloudFormation stack and make clean-all will remove the stack and the bucket.

I've also included a few utility targets:

  • make invoke FUNCTION=foo invokes the function foo on AWS.
  • make invoke-local FUNCTION=foo invokes the function foo on sam-local.
  • make outputs displays the outputs of the CloudFormation stack. This is useful for picking up the API Gateway URL for instance, if you set it up in your template.yaml.
  • make lastlog FUNCTION=foo displays the logs for the last invocation of the function foo.
Parameters for template.yaml

I pass the PROJECT_NAME and UNIQUE_KEY through to the template as the parameters ProjectName and UniqueKey respectively. These are then set in the Parameters section of the template:

template.yaml:

Parameters: ProjectName: Type: String UniqueKey: Type: String

I then use them in the template when I need uniqueness, such as when creating an S3 bucket:

template.yaml:

Resources: ImagesBucket: Type: AWS::S3::Bucket Properties: BucketName: !Join [ '-', [!Ref "ProjectName", !Ref "UniqueKey", "files" ] ]

Which creates a bucket named "hello-world-1557903576-files" which nicely complements "hello-world-1557903576-brefapp".

Categories: Web Technologies

Pages