Archiwum kategorii: CSS

Mētis

Post pobrano z: Mētis

Kelly Sutton writes about programming, working with teams and the relationship to the Greek word Mētis:

Mētis is typically translated into English as “cunning” or “cunning intelligence.” While not wrong, this translation fails to do justice to the range of knowledge and skills represented by mētis. Broadly understood, mētis represents a wide array of practical skills and acquired intelligence in responding to a constantly changing natural and human environment.

Kelly continues:

In some ways, mētis is at direct odds with processes that need a majority of the design up-front. Instead, it prefers an evolutionary design. This system of organization and building can be maddening to an organization looking to suss out structure. The question of “When will Project X ship?” seems to be always met with weasel words and hedges.

A more effective question—although equally infuriating to the non-engineering members of the company—would be “When will our understanding of the problem increase an order of magnitude, and when will that understanding be built into the product?”

Direct Link to ArticlePermalink


Mētis is a post from CSS-Tricks

Gutenberg

Post pobrano z: Gutenberg

I’ve only just been catching up with the news about Gutenberg, the name for a revamp of the WordPress editor. You can use it right now, as it’s being built as a plugin first, with the idea that eventually it goes into core. The repo has better information.

It seems to me this is the most major change to the WordPress editor in WordPress history. It also seems particularly relevant here as we were just talking about content blocks and how different CMS’s handle them. That’s exactly what Gutenberg is: a content block editor.

Rather than the content area being a glorified <textarea> (perhaps one of the most valid criticisms of WordPress), the content area becomes a wrapper for whatever different „blocks” you want to put there. Blocks are things like headings, text, lists, and images. They are also more elaborate things like galleries and embeds. Crucially, blocks are extensible and really could be anything. Like a [shortcode], I imagine.

Some images from Brian Jackson’s Diving Into the New Gutenberg WordPress Editor help drive it home:

As with any big software change, it’s controversial (even polarizing). I received an email from someone effectively warning me about it.

The consensus is this UI upgrade could either move WP into the future or alienate millions of WP site owners and kill WordPress.

I tend to think WordPress is 2-BIG-2-DIE, so probably the former.

I also think piecing together block types is a generic and smart abstraction for a CMS to make. Gutenberg seems to be handling it in a healthy way. The blocks are simply wrapped in specially formatted <!-- wp:core/text --> <!-- /wp:core/text --> to designate a block, so that the content highly compatible. A WordPress site without Gutenberg won’t have any trouble with it, nor porting it elsewhere.

Plus the content is still treated in templates as one big chunk:

To ensure we keep a key component of WordPress’ strength intact, the source of truth for the content should remain in post_content, where the bulk of the post data needs to be present in a way that is accessible and portable.

So regardless of how you structure it in the editor, it’s stored as a chunk in the database and barfed out in templates with one command. That makes it perhaps less flexible than you might want from a templating perspective, but scopes down this change to a paleteable level and remains very WordPress-y.

It seems a lot of the controversy stems from either who moved my cheese sentiments or what it does and doesn’t support at this second. I don’t put much stock in either, as people tend to find the cheese fairly quickly and this still under what seems to be heavy active development.

A big support worry is custom meta boxes. Joost de Valk:

Fact remains that, if you test Gutenberg right now, you’ll see that Yoast SEO is not on the page, anywhere. Nor, for that matter, are all the other plugins you might use like Advanced Custom Fields or CMB2. All of these plugins use so-called meta boxes, the boxes below and to the side of the current editor.

The fact that the Gutenberg team is considering changing meta boxes is, in our eyes, a big mistake. This would mean that many, many plugins would not work anymore the minute Gutenberg comes out. Lots and lots of custom built integrations would stop working. Hundreds of thousands of hours of development time would have to be, at least partly, redone. All of this while, for most sites, the current editor works just fine.

That does sound like a big deal. I wonder how easy baby stepping into Gutenberg will be. For example, enabling it for standard posts and pages while leaving it off for custom post types where you are more likely to need custom meta boxes (or some combination like that).

On this site, I make fairly heavy use of custom meta boxes (even just classic custom fields), as well as using my own HTML in the editor, so Gutenberg won’t be something I can hop on quickly. Which makes me wonder if there will always be a „classic” editor or if the new editor will be mandatory at a certain point release.

Yet more controversy came from the React licensing stuff. That went essentially like:

  1. Matt Mullenweg: we’re gonna switch away from React (which Gutenberg uses) because licencing.
  2. React: You’re all wrong but we give up. It’s MIT now.
  3. Matt Mullenweg: That’s good, but the talk now is allowing people to use whatever New JavaScript lib they want.

I’ve never heard of „framework-agnostic” block rendering, but apparently, it’s a thing. Or maybe it’s not? Omar Reiss:

With the new Gutenberg editor we’re changing the way the WordPress admin is being built. Where we now render the interface with PHP, we will start rendering more and more on the client side with JavaScript. After the editor, this is likely to become true for most of the admin. That means that if you want to integrate with the admin interface, you’ll have to integrate with the JavaScript that renders the interface. If WordPress chooses Vue, you’ll have to feed WordPress Vue components to render. If WordPress chooses React, you’ll have to feed WordPress React components to render. These things don’t go together. React doesn’t render Vue components or vice versa. There is no library that does both. If WordPress uses a particular framework, everyone will have to start using that framework in order to be able to integrate.

That’s a tricky situation right there. Before the React license change, I bet a nickel they’d go Vue. After, I suspect they’ll stick with React. Their own Calypso is all React in addition to what already exists for Gutenberg, so it seems like a continuity bonus.

This will be a fun tech story to follow! Sites like Post Status will likely be covering it closer than I’ll be able to.


Gutenberg is a post from CSS-Tricks

Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions

Post pobrano z: Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions

I work on a large team with amazing people like Simona Cotin, John Papa, Jessie Frazelle, Burke Holland, and Paige Bailey. We all speak a lot, as it’s part of a developer advocate’s job, and we’re also frequently asked where we’ll be speaking. For the most part, we each manage our own sites where we list all of this speaking, but that’s not a very good experience for people trying to explore, so I made a demo that makes it easy to see who’s speaking, at which conferences, when, with links to all of this information. Just for fun, I made use of three.js so that you can quickly visualize how many places we’re all visiting.

You can check out the live demo here, or explore the code on GitHub.

In this tutorial, I’ll run through how we set up the globe by making use of a Serverless function that gets geolocation data from Google for all of our speaking locations. I’ll also run through how we’re going to use Vuex (which is basically Vue’s version of Redux) to store all of this data and output it to the table and globe, and how we’ll use computed properties in Vue to make sorting through that table super performant and slick.

Article Series:

  1. Automatically Update GitHub Files With Serverless Functions (you are here!)
  2. Filtering and Using the Data (coming soon!)

Serverless Functions

What the heck?

Recently I tweeted that „Serverless is an actually interesting thing with the most clickbaity title.” I’m going to stand by that here and say that the first thing anyone will tell you is that serverless is a misnomer because you’re actually still using servers. This is true. So why call it serverless? The promise of serverless is to spend less time setting up and maintaining a server. You’re essentially letting the service handle maintenance and scaling for you, and you boil what you need down to functions that state: when this request comes in, run this code. For this reason, sometimes people refer to them as functions as a service, or FaaS.

Is this useful? You bet! I love not having to babysit a server when it’s unnecessary, and the payment scales automatically as well, which means you’re not paying for anything you’re not using.

Is FaaS the right thing to use all the time? Eh, not exactly. It’s really useful if you’d like to manage small executions. Serverless functions can retrieve data, they can send email notifications, they can even do things like crop images on the fly. But for anything where you have processes that might hold up resources or a ton of computation, being able to communicate with a server as you normally do might actually be more efficient.

Our demo here is a good example of something we’d want to use serverless for, though. We’re mostly just maintaining and updating a single JSON file. We’ll have all of our initial speaker data, and we need to get geolocation data from Google to create our globe. We can have it all work triggered with GitHub commits, too. Let’s dig in.

Creating the Serverless Function

We’re going to start with a big JSON file that I outputted from a spreadsheet of my coworker’s speaking engagements. That file has everything I need in order to make the table, but for the globe I’m going to use this webgl-globe from Google data arts that I’ll modify. You can see in the readme that eventually I’ll format my data to extract the years, but I’ll also need the latitude and longitude of every location we’re visiting

var data = [
    [
    'seriesA', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ],
    [
    'seriesB', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ]
];

Eventually, I’ll also have to reduce the duplicated instances per year to make the magnitude, but we’ll tackle that modification of our data within Vue in the second part of this series.

To get started, if you haven’t already, create a free Azure trial account. Then go to the portal: ms.portal.azure.com

Inside, you’ll see a sidebar that has a lot of options. At the top it will say new. Click that.

Showing the sidebar in Azure where you can create a new service

Next, we’ll select function app from the list and fill in the new name of our function. This will give us some options. You can see that it will already pick up our resource group, subscription, and create a storage account. It will also use the location data from the resource group so, happily, it’s pretty easy to populate, as you can see in the GIF below.

Create a new function

The defaults are probably pretty good for your needs. As you can see in the GIF above, it will autofill most of the fields just from the App name. You may want to change your location based on where most of your traffic is coming from, or from a midpoint (i.e. if you have a lot of traffic both in San Francisco and New York), it might be best to choose a location in the middle of the United States.

The hosting plan can be Consumption (the default) or App Service Plan. I choose Consumption because resources are added or subtracted dynamically, which the magic of this whole serverless thing. If you’d like a higher level of control or detail, you’d probably want the App Service plan, but keep in mind that this means you’ll be manually scaling and adding resources, so it’s extra work on your part.

Modify the function once it's created

You’ll be taken to a screen that shows you a lot of information about your function. Check to see that everything is in order, and then click the functions plus sign on the sidebar.

Add in the actual function

From there you’ll be able to pick a template, we’re going to page down a bit and pick GitHub Webhook – JavaScript from the options given.

choose the github javascript template from the templates in the portal

Selecting this will bring you to a page with an `index.js` file. You’ll be able to enter code if you like, but they give us some default code to run an initial test to see everything’s working properly. Before we create our function, let’s first test it out to see that everything looks ok.

New default template

We’ll hit the save and run buttons at the top, and here’s what we get back. You can see the output gives us a comment, we get a status of 200 OK in green, and we get some logs that validate our GitHub webhook successfully triggered.

testing the default output

Pretty nice! Now here’s the fun part: let’s write our own function.

Writing our First Serverless Function

In our case, we have the location data for all of the speeches, which we need for our table, but in order to make the JSON for our globe, we will need one more bit of data: we need latitude and longitude for all of the speaking events. The JSON file will be read by our Vuex central store, and we can pass out the parts that need to be read to each component.

The file that I used for the serverless function is stored in my github repo, you can explore the whole file here, but let’s also walk through it a bit:

The first thing I’ll mention is that I’ve populated these variables with config options for the purposes of this tutorial because I don’t want to give you all my private info. I mean, it’s great, we’re friends and all, but I just met you.

// GitHub configuration is read from process.env
let GH_USER = process.env.GH_USER;
let GH_KEY = process.env.GH_KEY;
let GH_REPO = process.env.GH_REPO;
let GH_FILE = process.env.GH_FILE;

In a real world scenario, I could just drop in the data:

// GitHub configuration is read from process.env
let GH_USER = sdras;

… and so on. In order to use these environment variables (in case you’d also like to store them and keep them private), you can use them like I did above, and go to your function in the dashboard. There you will see an area called Configured Features. Click application settings and you’ll be taken to a page with a table where you can enter this information.

Working with our dataset

First, we’ll retrieve the original JSON file from GitHub and decode/parse it. We’re going to use a method that gets the file from a GitHub response and base64 encodes it (more information on that here).

module.exports = function(context, data) {
 // Make the context available globally
 gContext = context;

 getGithubJson(githubFilename(), (data, err) => {
   if (!err) {
     // No error; base64 decode and JSON parse the data from the Github response
     let content = JSON.parse(
       new Buffer(data.content, 'base64').toString('ascii')
     );

Then we’ll retrieve the geo-information for each item in the original data, if it went well, we’ll push it back up to GitHub, otherwise, it will error. We’ll have two errors: one for a general error, and another for if we get a correct response but there is a geo error, so we can tell them apart. You’ll note that we’re using gContext.log to output to our portal console.

getGeo(makeIterator(content), (updatedContent, err) => {
       if (!err) {
         // we need to base64 encode the JSON to embed it into the PUT (dear god, why)
         let updatedContentB64 = new Buffer(
           JSON.stringify(updatedContent, null, 2)
         ).toString('base64');
         let pushData = {
           path: GH_FILE,
           message: 'Looked up locations, beep boop.',
           content: updatedContentB64,
           sha: data.sha
         };
         putGithubJson(githubFilename(), pushData, err => {
           context.log('All done!');
           context.done();
         });
       } else {
         gContext.log('All done with get Geo error: ' + err);
         context.done();
       }
     });
   } else {
     gContext.log('All done with error: ' + err);
     context.done();
   }
 });
};

Great! Now, given an array of entries (wrapped in an iterator), we’ll walk over each of them and populate the latitude and longitude, using Google Maps API. Note that we also cache locations to try and save some API calls.

function getGeo(itr, cb) {
 let curr = itr.next();
 if (curr.done) {
   // All done processing- pass the (now-populated) entries to the next callback
   cb(curr.data);
   return;
 }

 let location = curr.value.Location;

Now let’s check the cache to see if we’ve already looked up this location:

 if (location in GEO_CACHE) {
   gContext.log(
     'Cached ' +
       location +
       ' -> ' +
       GEO_CACHE[location].lat +
       ' ' +
       GEO_CACHE[location].long
   );
   curr.value.Latitude = GEO_CACHE[location].lat;
   curr.value.Longitude = GEO_CACHE[location].long;
   getGeo(itr, cb);
   return;
 }

Then if there’s nothing found in cache, we’ll do a lookup and cache the result, or let ourselves know that we didn’t find anything:

 getGoogleJson(location, (data, err) => {
   if (err) {
     gContext.log('Error on ' + location + ' :' + err);
   } else {
     if (data.results.length > 0) {
       let info = {
         lat: data.results[0].geometry.location.lat,
         long: data.results[0].geometry.location.lng
       };
       GEO_CACHE[location] = info;
       curr.value.Latitude = info.lat;
       curr.value.Longitude = info.long;
       gContext.log(location + ' -> ' + info.lat + ' ' + info.long);
     } else {
       gContext.log(
         "Didn't find anything for " + location + ' ::' + JSON.stringify(data)
       );
     }
   }
   setTimeout(() => getGeo(itr, cb), 1000);
 });
}

We’ve made use of some helper functions along the way that help get Google JSON, and get and put GitHub JSON.

Now if we run this function in the portal, we’ll see our output:

Running the function and seeing the console: status 200 ok

It works! Our serverless function updates our JSON file with all of the new data. I really like that I can work with backend services without stepping outside of JavaScript, which is familiar to me. We need only git pull and we can use this file as the state in our Vuex central store. This will allow us to populate the table, which we’ll tackle the next part of our series, and we’ll also use that to update our globe. If you’d like to play around with a serverless function and see it in action for yourself, you can create one with a free trial account.

Stay tuned for the next installment!

Article Series:

  1. Automatically Update GitHub Files With Serverless Functions (you are here!)
  2. Filtering and Using the Data (coming soon!)

Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions is a post from CSS-Tricks

A Five Minutes Guide to Better Typography

Post pobrano z: A Five Minutes Guide to Better Typography

Pierrick Calvez with, just maybe, a bunch of typographic advice that you’ve heard before. But this is presented very lovingly and humorously.

Repeating the basics with typography feels important in the same way repeating the basics of performance does. Gzip your stuff. Make your line length readable. Set far expires headers. Make sure you have hierarchy. Optimize your images. Align left.

Let’s repeat this stuff until people actually do it.

Direct Link to ArticlePermalink


A Five Minutes Guide to Better Typography is a post from CSS-Tricks

Help Your Users `Save-Data`

Post pobrano z: Help Your Users `Save-Data`

The breadth and depth of knowledge to absorb in the web performance space is ridiculous. At a minimum, I’m discovering something new nearly every week. Case in point: The Save-Data header, which I discovered via a Google Developers article by Ilya Grigorik.

If you’re looking for the tl;dr version of how Save-Data works, let me oblige you: If you opt into data savings on the Android version of Chrome (or the Data Saver extension on your desktop device), every request that Chrome sends to a server will contain a Save-Data header with a value of On. You can then act on this header to change your site’s content delivery in such a way that conserves data for the user. This is a very open-ended sort of opportunity that you’re being given, so let’s explore a few ways that you could act on the Save-Data header to send less bytes down the wire!

Change your image delivery strategy

I don’t know if you’ve noticed, but images are often the largest chunk of the total payload of any given page. So perhaps the most impactful step you can take with Save-Data is to change how images are delivered. What I settled on for my blog was to rewrite requests for high DPI images to low DPI images. When I serve image sets like this on my site, I do so using the <picture> element to serve WebP images with a JPEG or PNG fallback like so:

<picture>
  <source srcset="/img/george-and-susan-1x.webp 1x, /img/george-and-susan-2x.webp 2x">
  <source srcset="/img/george-and-susan-1x.jpg 1x, /img/george-and-susan-2x.jpg 2x">
  <img src="/img/george-and-susan-1x.jpg" alt="LET'S NOT GET CRAZY HERE" width="320" height="240">
</picture>

This solution is backed by tech that’s baked into modern browsers. The <picture> element delivers the optimal image format according to a browser’s capabilities, while srcset will help the browser decide what looks best for any given device’s screen. Unfortunately, both <picture> and srcset lacks control over which image source to serve for users who want to save data. Nor should they! That’s not the job of srcset or <picture>.

This is where Save-Data comes in handy. When users visit my site and send a Save-Data request header, I use mod_rewrite in Apache to serve low DPI images in lieu of high DPI ones:

RewriteCond %{HTTP:Save-Data} =on [NC]
RewriteRule ^(.*)-2x.(png|jpe?g|webp)$ $1-1x.$2 [R=302,L]

If you’re unfamiliar with mod_rewrite, the first line is a condition that checks if the Save-Data header is present and contains a value of on. The [NC] flag merely tells mod_rewrite to perform a case-insensitive match. If the condition is met, the RewriteRule looks for any requests for a PNG, JPEG or WebP asset ending in -2x (the high DPI version), and redirects such requests to an asset ending in -1x (the low DPI version). The R=302 flag signals to the browser that this is a temporary (302) redirect. Since the user can toggle Data Saver on or off at will, we don’t want to send a permanent (301) redirect, as the browser will cache it. Caching the redirect ensures that it will be in effect even if Data Saver is turned off later on.

Image delivery with Save-Data turned on

Aren’t redirects bad for performance? Most of the time, yes. Redirects add to latency because it takes longer for a request to be resolved. In this instance, however, it’s a fitting solution. We don’t want to rewrite requests without redirecting them because then low-quality images get cached under the same URLs as high-quality ones. What if the user connects to a wifi network, turns off Data Saver, and return to the site at a later time? The low-quality image will be served from the cache, even when Data Saver is turned off. That’s not at all what we want. If the user isn’t using Data Saver, we should assume the default image delivery strategy.

Of course, there are other ways you could change your image delivery in the presence of Save-Data. For example, Cory Dowdy wrote a post detailing how he uses Save-Data to serve lower quality images. Save-Data gives you lots of room to devise an image delivery strategy that makes the best sense for your site or application.

Opt out of server pushes

Server push is good stuff if you’re on HTTP/2 and can use it. It allows you send assets to the client before they ever know they need them. The problem with it, though, is it can be weirdly unpredictable in select scenarios. On my site, I use it to push CSS only, and this generally works well. Although, I do tailor my push strategy in Apache to avoid browsers that have issues with it (i.e., Safari) like so:

<If "%{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">
  Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style; nopush"
</If>
<Else>
  Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style"
</Else>

In this instance, I’m saying „Hey, I want you to preemptively push my site’s CSS to people, but only if they’re not using Safari.” Even if Safari users come by, they’ll still get a preload resource hint (albeit with a nopush attribute to discourage my server from pushing anything).

Even so, it would behoove us to be extra cautious when it comes to pushing assets for users with Data Saver turned on. In the case of my blog, I decided I wouldn’t push anything to anyone who had Data Saver enabled. To accomplish this, I made the following change to the initial <If> header:

<If "%{HTTP:Save-Data} == 'on' || %{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">

This is the same as my initial configuration, but with an additional condition that says „Hey, if Save-Data is present and set to a value of on, don’t be pushing that stylesheet. Just preload it instead.” It might not be a big change, but it’s one of those little things that could help visitors to avoid wasted data if a push was in vain for any reason.

Change how you deliver markup

With Save-Data, you could elect to change what parts of the document you deliver. This presents all sorts of opportunities, but before you can embark on this errand, you’ll need to check for the Save-Data header in a back end language. In PHP, such a check might look something like this:

$saveData = (isset($_SERVER["HTTP_SAVE_DATA"]) && stristr($_SERVER["HTTP_SAVE_DATA"], "on") !== false) ? true : false;

On my blog, I use this $saveData boolean in various places to remove markup for images that aren’t crucial to the content of a given page. For example, one of my articles has some animated GIFs and other humorous images that are funny little flourishes for users who don’t mind them. But they are heavy, and not really necessary to communicate the central point of the article. I also remove the header illustration and a teeny tiny thumbnail of my book from the nav.

Image markup delivery with Data Saver on and off

From a payload perspective, this can certainly have a profound effect:

The potential effects of Data Saver on page payload

Another opportunity would be to use the aforementioned $saveData boolean to put a save-data class on the <html> element:

<html class="<?php if($saveData === true) : echo("save-data"); endif; ?>">

With this class, I could then write styles that could change what assets are used in background-image properties, or any CSS property that references external assets. For example:

/* Just a regular ol' background image */
body {
  background-image: url("/images/bg.png");
}

/* A lower quality background image for users with Data Saver turned on */
.save-data body {
  background-image: url("/images/bg-lowsrc.png");
}

Markup isn’t the only thing you could modify the delivery of. You could do the same for videos, or even do something as simple as delivering fewer search results per page. It’s entirely up to you!

Conclusion

The Save-Data header gives you a great opportunity to lend a hand to users who are asking you to help them, well, save data. You could use URL rewriting to change media delivery, change how you deliver markup, or really just about anything that you could think of.

How will you help your users Save-Data? Leave a comment and let your ideas be heard!


Cover of Web Performance in Action

Jeremy Wagner is the author of Web Performance in Action, available now from Manning Publications. Use promo code sswagner to save 42%.

Check him out on Twitter: @malchata


Help Your Users `Save-Data` is a post from CSS-Tricks

Boilerform

Post pobrano z: Boilerform

This is just a random idea, but I can’t stop it from swirling around in my head.

Whenever I need to style a form on a fresh project where the CSS and style guide stuff is just settling in, the temptation to reach for a mini form framework is strong. Form elements are finicky, have little cross-browser issues, and are sometimes downright hard to wrassle styling control from.

This idea, which I’m just now managing to write about, but haven’t actually done any work toward, would be this mini form framework. Maybe something like „Boilerform”, as Dave jokingly suggested on an episode of ShopTalk.

I imagine it something like this:

  1. It would have basic form styling to organize form elements, not unlike something like Foundation forms.
  2. It would account for cross browser issues, not unlike normalize.css.
  3. It would include strongarming styling control over form elements, not unlike WTF, forms?
  4. It would include native browser form validation stuff, including UX improvements via native JavaScript API’s, not unlike Validate.js.

I think there is value in combining those things into one thing, but doing so…

  1. With a light touch, being as unopinionated about the final styling as possible
  2. With flexibility, perhaps showing off a gallery of different form types with different styling.

I probably don’t have time to head up a project like this, but I wouldn’t mind helping connect humans who also see value here and wanna give it a shot.


Boilerform is a post from CSS-Tricks

eBay’s Font Loading Strategy

Post pobrano z: eBay’s Font Loading Strategy

Senthil Padmanabhan documents how:

  1. Both FOUT and FOIT are undesirable.
  2. The best solution to that is font-display.
  3. Since font-display isn’t well supported, the path to get there is very complicated.
  4. They open sourced it.

They went with replicating font-display: optional, my favorite as well.

Direct Link to ArticlePermalink


eBay’s Font Loading Strategy is a post from CSS-Tricks

5 things CSS developers wish they knew before they started

Post pobrano z: 5 things CSS developers wish they knew before they started

You can learn anything, but you can't learn everything 🙃

So accept that, and focus on what matters to you

— Una Kravets 👩🏻‍💻 (@Una) September 1, 2017

Una Kravets is absolutely right. In modern CSS development, there are so many things to learn. For someone starting out today, it’s hard to know where to start.

Here is a list of things I wish I had known if I were to start all over again.

1. Don’t underestimate CSS

It looks easy. After all, it’s just a set of rules that selects an element and modifies it based on a set of properties and values.

CSS is that, but also so much more!

A successful CSS project requires the most impeccable architecture. Poorly written CSS is brittle and quickly becomes difficult to maintain. It’s critical you learn how to organize your code in order to create maintainable structures with a long lifespan.

But even an excellent code base has to deal with the insane amount of devices, screen sizes, capabilities, and user preferences. Not to mention accessibility, internationalization, and browser support!

CSS is like a bear cub: cute and inoffensive but as he grows, he’ll eat you alive.

  • Learn to read code before writing and delivering code.
  • It’s your responsibility to stay up to date with best practice. MDN, W3C, A List Apart, and CSS-Tricks are your source of truth.
  • The web has no shape; each device is different. Embrace diversity and understand the environment we live in.

2. Share and participate

Sharing is so important! How I wish someone had told me that when I started. It took me ten years to understand the value of sharing; when I did, it completely changed how I viewed my work and how I collaborate with others.

You’ll be a better developer if you surround yourself with good developers, so get involved in open source projects. The CSS community is full of kind and generous developers. The sooner the better.

Share everything you learn. The path is as important as the end result; even the tiniest things can make a difference to others.

  • Learn Git. Git is the language of open source and you definitely want to be part of it.
  • Get involved in an open source project.
  • Share! Write a blog, documentation, or tweets; speak at meetups and conferences.
  • Find an accountability partner, someone that will push you to share consistently.

3. Pick the right tools

Your code editor should be an extension of your mind.

It doesn’t matter if you use Atom, VSCode or old school Vim; the better you shape your tool to your thought process, the better developer you’ll become. You’ll not only gain speed but also have an uninterrupted thought line that results in fluid ideas.

The terminal is your friend.

There is a lot more about being a CSS developer than actually writing CSS. Building your code, compiling, linting, formatting, and browser live refresh are only a small part of what you’ll have to deal with on a daily basis.

  • Research which IDE is best for you. There are high performance text editors like Vim or easier to use options like Atom or VSCode.
  • Pick up your way around the terminal and learn CLI as soon as possible. The short book „Working the command line” is a great starting point.

4. Get to know the browser

The browser is not only your canvas, but also a powerful inspector to debug your code, test performance, and learn from others.

Learning how the browser renders your code is an eye-opening experience that will take your coding skills to the next level.

Every browser is different; get to know those differences and embrace them. Love them for what they are. (Yes, even IE.)

  • Spend time looking around the inspector.
  • You’ll not be able to own every single device; get a BrowserStack or CrossBrowserTesting account, it’s worth it.
  • Install every browser you can and learn how each one of them renders your code.

5. Learn to write maintainable CSS

It’ll probably take you years, but if there is just one single skill a CSS developer should have, it is to write maintainable structures.

This means knowing exactly how the cascade, the box model, and specificity works. Master CSS architecture models, learn their pros and cons and how to implement them.

Remember that a modular architecture leads to independent modules, good performance, accessible structures, and responsive components (AKA: CSS happiness).

The future looks bright

Modern CSS is amazing. Its future is even better. I love CSS and enjoy every second I spend coding.

If you need help, you can reach out to me or probably any of the CSS developers mentioned in this article. You might be surprised by how kind and generous the CSS community can be.

What do you think about my advice? What other advice would you give? Let me know what you think in the comments.


5 things CSS developers wish they knew before they started is a post from CSS-Tricks

Designing Websites for iPhone X

Post pobrano z: Designing Websites for iPhone X

We’ve already covered „The Notch” and the options for dealing with it from an HTML and CSS perspective. There is a bit more detail available now, straight from the horse’s mouth:

Safe area insets are not a replacement for margins.

… we want to specify that our padding should be the default padding or the safe area inset, whichever is greater. This can be achieved with the brand-new CSS functions min() and max() which will be available in a future Safari Technology Preview release.

@supports(padding: max(0px)) {
    .post {
        padding-left: max(12px, constant(safe-area-inset-left));
        padding-right: max(12px, constant(safe-area-inset-right));
    }
}

It is important to use @supports to feature-detect min and max, because they are not supported everywhere, and due to CSS’s treatment of invalid variables, to not specify a variable inside your @supports query.

Jeremey Keith’s hot takes have been especially tasty, like:

You could add a bunch of proprietary CSS that Apple just pulled out of their ass.

Or you could make sure to set a background colour on your body element.

I recommend the latter.

And:

This could be a one-word article: don’t.

More specifically, don’t design websites for any specific device.

Although if this pushes support forward for min() and max() as generic functions, that’s cool.

Direct Link to ArticlePermalink


Designing Websites for iPhone X is a post from CSS-Tricks