Archive

Author Archive

10 Typography Trends for 2019

December 10th, 2018 No comments
Typography Trends

Can you hear that? That’s the sweet sound of jingle bells followed by the explosion of fireworks. The combination of these two sounds can only mean one thing: 2019 is right around the corner. That might sound a little scary, but I can assure you that this article contains nothing but good vibes and happy thoughts.

As a designer, you’re probably pretty aware that you should be keeping up with trends, right? I certainly hope so. But, that doesn’t mean that you can’t put a little personal flare on those trends. For the purpose of this article, and because the title already says typography trends for 2019, we’re going to discuss… you guessed it: typography trends for 2019. This list is in no particular order. It will contain new trends and a few classics that you totally need to stick with. Fasten your seatbelts, explorers, we’re diving straight in.

Handwritten fonts

We’re going to start this list off with a style of font that will most likely be a trend for many years to come. Handwritten fonts are great because they allow you to put your own touch on your brand, and they bring with them a sense of detail that other fonts can’t. Granted, a handwritten font may not look so great on the side of a corporate office building, but they certainly are a great way to reach out to your audience on a more personal level.

Typography Trends

Vintage fonts

Vintage fonts are also a timeless classic that deserves a spot of any typography trends lists ever. The reason people are so drawn to vintage fonts is very similar to the reason they’re so drawn to handwritten fonts. The difference here is that the audience is most likely already familiar with the font, as it is vintage. Instead of making new connections using a handwritten touch, you renew old connections by going vintage.

Typography Trends

Watercolor fonts

Watercolor fonts have risen in popularity almost side-by-side with handwritten fonts because they go so well together. Watercolors have recently existed mainly in the background of a few web pages. But now, people are starting to use them in the spotlight. Watercolor fonts are a great way to portray calm, cool, and collected vibes. They take away from the seriousness of business and add to the homely feel.

Typography Trends

Serif fonts

Serifs again are nothing new. In fact, they’re probably one of the oldest typography trends we can dig up. They are, however, a trend that’s making a comeback. Serifs can vary depending on how extra you want to be, but they’re another great way to put a little more flare on your work.

Typography Trends

Big and small font types… together?

Yes, it’s true. A lot of people are instantly attracted to things that match or at least are the same size. The idea behind using both big and small fonts together isn’t exactly a new thing, but it has made great headway over the years. Because the letters in the font don’t match up, it can grab someone’s attention quicker than a buy-one-get-one sale at Old Navy. plus, it’s a creative way to put emphasis on a particular part of your brand or logo.

Typography Trends

Variable fonts

In addition to the variation in size, the mix-match of different font types has become a design phenomenon. I mean, why stick to just one font if you’ve found a few that you like? If done correctly, you’ll be able to mix a number of different fonts together and create your own personal masterpiece. Just try not to be too overwhelming.

Typography Trends

Color fonts

For too long black and white fonts have haunted our screens! Okay, maybe that’s a little dramatic, but sometimes we just need a little color. Color fonts have been popular on and off for forever, and they’re starting to make a massive comeback. Color fonts allow us to be that much more creative with our projects. They can say as little or as much as you want them to about the letters that they’re highlighting. They’re the perfect way to snag someone’s attention in a crowd full of black and white.

Typography Trends

Cutouts and overlays

Everyone wants to add layers to their designs, and it’s for good reason. People don’t want to sit and stare at a flat-looking, boring, underwhelming webpage. They want to be wowed and wanting more. Cutouts and overlays are a great way to give that 3-dimensional effect without having to wear the glasses that hurt your eyes after 30 minutes. They give you yet another layer to be creative with, and thus attracting more attention.

Typography Trends

Geometric fonts

While handwritten fonts and different sized lettering are cool, perfectly straight lines and rounded corners will always be one of the typography trends, too. Don’t get me wrong, though, geometric fonts leave plenty of room to be creative. Geometric fonts have grown exponentially over the past year or two, and I don’t see them slowing down anytime soon.

Typography Trends

Customize everything

If you have the extra cash to shell out, customizing your brand is a great way to set your own trends. I’m not talking about just logotypes here, I literally mean customize everything. What better way to give people a new experience than to create one custom for your brand? You’re a designer, challenge yourself!

Bring in the New Year right

Again, these typography trends aren’t in any particular order, but they are all super duper sweet. Trends are made every day. While some of us choose to follow those trends, others create their own path for us to follow in the future. The #1 rule of design is to be yourself and create your best work. Design something that you’re proud of, and show it off to the word.

Read More at 10 Typography Trends for 2019

Categories: Designing, Others Tags:

An Introduction and Guide to the CSS Object Model (CSSOM)

December 10th, 2018 No comments
The CSSStyleDeclaration API in the DevTools console

If you’ve been writing JavaScript for some time now, it’s almost certain you’ve written some scripts dealing with the Document Object Model (DOM). DOM scripting takes advantage of the fact that a web page opens up a set of APIs (or interfaces) so you can manipulate and otherwise deal with elements on a page.

But there’s another object model you might want to become more familiar with: The CSS Object Model (CSSOM). Likely you’ve already used it but didn’t necessarily realize it.

In this guide, I’m going to go through many of the most important features of the CSSOM, starting with stuff that’s more commonly known, then moving on to some more obscure, but practical, features.

What is the CSSOM?

According to MDN:

The CSS Object Model is a set of APIs allowing the manipulation of CSS from JavaScript. It is much like the DOM, but for the CSS rather than the HTML. It allows users to read and modify CSS style dynamically.

MDN’s info is based on the official W3C CSSOM specification. That W3C document is a somewhat decent way to get familiar with what’s possible with the CSSOM, but it’s a complete disaster for anyone looking for some practical coding examples that put the CSSOM APIs into action.

MDN is much better, but still largely lacking in certain areas. So for this post, I’ve tried to do my best to create useful code examples and demos of these interfaces in use, so you can see the possibilities and mess around with the live code.

As mentioned, the post starts with stuff that’s already familiar to most front-end developers. These common features are usually lumped in with DOM scripting, but they are technically part of the larger group of interfaces available via the CSSOM (though they do cross over into the DOM as well).

Inline Styles via element.style

The most basic way you can manipulate or access CSS properties and values using JavaScript is via the style object, or property, which is available on all HTML elements. Here’s an example:

document.body.style.background = 'lightblue';

Most of you have probably seen or used that syntax before. I can add to or change the CSS for any object on the page using that same format: element.style.propertyName.

In that example, I’m changing the value of the background property to lightblue. Of course, background is shorthand. What if I want to change the background-color property? For any hyphenated property, just convert the property name to camel case:

document.body.style.backgroundColor = 'lightblue';

In most cases, a single-word property would be accessed in this way by the single equivalent word in lowercase, while hyphenated properties are represented in camel case. The one exception to this is when using the float property. Because float is a reserved word in JavaScript, you need to use cssFloat (or styleFloat if you’re supporting IE8 and earlier). This is similar to the HTML for attribute being referenced as htmlFor when using something like getAttribute().

Here’s a demo that uses the style property to allow the user to change the background color of the current page:

See the Pen Using the style Object to Change the Background Color by Louis Lazaris (@impressivewebs) on CodePen.

So that’s an easy way to define a CSS property and value using JavaScript. But there’s one huge caveat to using the style property in this way: This will only apply to inline styles on the element.

This becomes clear when you use the style property to read CSS:

document.body.style.backgroundColor = 'lightblue';
console.log(document.body.style.backgroundColor);
// "lightblue"

In the example above, I’m defining an inline style on the element, then I’m logging that same style to the console. That’s fine. But if I try to read another property on that element, it will return nothing — unless I’ve previously defined an inline style for that element in my CSS or elsewhere in my JavaScript. For example:

console.log(document.body.style.color);
// Returns nothing if inline style doesn't exist

This would return nothing even if there was an external stylesheet that defined the color property on the element, as in the following CodePen:

See the Pen element.style Reads Only Inline Styles by Louis Lazaris (@impressivewebs) on CodePen.

Using element.style is the simplest and most common way to add styles to elements via JavaScript. But as you can see, this clearly has some significant limitations, so let’s look at some more useful techniques for reading and manipulating styles with JavaScript.

Getting Computed Styles

You can read the computed CSS value for any CSS property on an element by using the window.getComputedStyle() method:

window.getComputedStyle(document.body).background;
// "rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box"

Well, that’s an interesting result. In a way, window.getComputedStyle() is the style property’s overly-benevolent twin. While the style property gives you far too little information about the actual styles on an element, window.getComputedStyle() can sometimes give you too much.

See the Pen The getComputedStyle() Method Can Read any CSS Property by Louis Lazaris (@impressivewebs) on CodePen.

In the example above, the background property of the element was defined using a single value. But the getComputedStyle() method returns all values contained in background shorthand. The ones not explicitly defined in the CSS will return the initial (or default) values for those properties.

This means, for any shorthand property, window.getComputedStyle() will return all the initial values, even if none of them is defined in the CSS:

See the Pen window.getComputedStyle() Returns All Longhand Values for a Shorthand Property by Louis Lazaris (@impressivewebs) on CodePen.

Similarly, for properties like width and height, it will reveal the computed dimensions of the element, regardless of whether those values were specifically defined anywhere in the CSS, as the following interactive demo shows:

See the Pen window.getComputedStyle() Returns Width and Height Values Even if Not Defined in the CSS by Louis Lazaris (@impressivewebs) on CodePen.

Try resizing the parent element in the above demo to see the results. This is somewhat comparable to reading the value of window.innerWidth, except this is the computed CSS for the specified property on the specified element and not just a general window or viewport measurement.

There are a few different ways to access properties using window.getComputedStyle(). I’ve already demonstrated one way, which uses dot-notation to add the camel-cased property name to the end of the method. You can see three different ways to do it in the following code:

// dot notation, same as above
window.getComputedStyle(el).backgroundColor;

// square bracket notation
window.getComputedStyle(el)['background-color'];

// using getPropertyValue()
window.getComputedStyle(el).getPropertyValue('background-color');

The first line uses the same format as in the previous demo. The second line is using square bracket notation, a common JavaScript alternative to dot notation. This format is not recommended and code linters will warn about it. The third example uses the getPropertyValue() method.

The first example requires the use of camel casing (although in this case both float and cssFloat would work) while the next two access the property via the same syntax as that used in CSS (with hyphens, often called “kebab case”).

Here’s the same demo as the previous, but this time using getPropertyValue() to access the widths of the two elements:

See the Pen Using window.getComputedStyle() along with getPropertyValue() by Louis Lazaris (@impressivewebs) on CodePen.

Getting Computed Styles of Pseudo-Elements

One little-known tidbit about window.getComputedStyle() is the fact that it allows you to retrieve style information on pseudo-elements. You’ll often see a window.getComputedStyle() declaration like this:

window.getComputedStyle(document.body, null).width;

Notice the second argument, null, passed into the method. Firefox prior to version 4 required a second argument, which is why you might see it used in legacy code or by those accustomed to including it. But it’s not required in any browser currently in use.

That second optional parameter is what allows me to specify that I’m accessing the computed CSS of a pseudo-element. Consider the following CSS:

.box::before {
  content: 'Example';
  display: block;
  width: 50px;
}

Here I’m adding a ::before pseudo-element inside the .box element. With the following JavaScript, I can access the computed styles for that pseudo-element:

let box = document.querySelector('.box');
window.getComputedStyle(box, '::before').width;
// "50px"

See the Pen Using getComputedStyle() to get styles from a pseudo-element by Louis Lazaris (@impressivewebs) on CodePen.

You can also do this for other pseudo-elements like ::first-line, as in the following code and demo:

let p = document.querySelector('.box p');
window.getComputedStyle(p, '::first-line').color;

See the Pen Using getComputedStyle() to get styles from a pseudo-element by Louis Lazaris (@impressivewebs) on CodePen.

And here’s another example using the ::placeholder pseudo-element, which apples to elements:

let input = document.querySelector('input');
window.getComputedStyle(input, '::placeholder').color

See the Pen Using getComputedStyle() to get styles from a ::placeholder pseudo-element by Louis Lazaris (@impressivewebs) on CodePen.

The above works in the latest Firefox, but not in Chrome or Edge (I’ve filed a bug report for Chrome).

It should also be noted that browsers have different results when trying to access styles for a non-existent (but valid) pseudo-element compared to a pseudo-element that the browser doesn’t support at all (like a made up ::banana pseudo-element). You can try this out in various browsers using the following demo:

See the Pen Testing getComputedStyle() on non-existent pseudo-elements by Louis Lazaris (@impressivewebs) on CodePen.

As a side point to this section, there is a Firefox-only method called getDefaultComputedStyle() that is not part of the spec and likely never will be.

The CSSStyleDeclaration API

Earlier when I showed you how to access properties via the style object or using getComputedStyle(), in both cases those techniques were exposing the CSSStyleDeclaration interface.

In other words, both of the following lines will return a CSSStyleDeclaration object on the document’s body element:

document.body.style;
window.getComputedStyle(document.body);

In the following screenshot you can see what the console produces for each of these lines:

The CSSStyleDeclaration API in the DevTools console

In the case of getComputedStyle(), the values are read-only. In the case of element.style, getting and setting the values is possible but, as mentioned earlier, these will only affect the document’s inline styles.

setProperty(), getPropertyValue(), and item()

Once you’ve exposed a CSSStyleDeclaration object in one of the above ways, you have access to a number of useful methods to read or manipulate the values. Again, the values are read-only in the case of getComputedStyle(), but when used via the style property, some methods are available for both getting and setting.

Consider the following code and demo:

let box = document.querySelector('.box');

box.style.setProperty('color', 'orange');
box.style.setProperty('font-family', 'Georgia, serif');
op.innerHTML = box.style.getPropertyValue('color');
op2.innerHTML = `${box.style.item(0)}, ${box.style.item(1)}`;

See the Pen Using Three Different Methods of the CSSStyleDeclaration API by Louis Lazaris (@impressivewebs) on CodePen.

In this example, I’m using three different methods of the style object:

  • The setProperty() method. This takes two arguments, each a string: The property (in regular CSS notation) and the value you wish to assign to the property.
  • The getPropertyValue() method. This takes a single argument: The property whose value you want to obtain. This method was used in a previous example using getComputedStyle(), which, as mentioned, likewise exposes a CSSStyleDeclaration object.
  • The item() method. This takes a single argument, which is a positive integer representing the index of the property you want to access. The return value is the property name at that index.

Keep in mind that in my simple example above, there are only two styles added to the element’s inline CSS. This means that if I were to access item(2), the return value would be an empty string. I’d get the same result if I used getPropertyValue() to access a property that isn’t set in that element’s inline styles.

Using removeProperty()

In addition to the three methods mentioned above, there are two others exposed on a CSSStyleDeclaration object. In the following code and demo, I’m using the removeProperty() method:

box.style.setProperty('font-size', '1.5em');
box.style.item(0) // "font-size"

document.body.style.removeProperty('font-size');
document.body.style.item(0); // ""

See the Pen Using the removeProperty() method of the CSSSTyleDeclaration API by Louis Lazaris (@impressivewebs) on CodePen.

In this case, after I set font-size using setProperty(), I log the property name to ensure it’s there. The demo then includes a button that, when clicked, will remove the property using removeProperty().

In the case of setProperty() and removeProperty(), the property name that you pass in is hyphenated (the same format as in your stylesheet), rather than camel-cased. This might seem confusing at first, but the value passed in is a string in this example, so it makes sense.

Getting and Setting a Property’s Priority

Finally, here’s an interesting feature that I discovered while researching this article: The getPropertyPriority() method, demonstrated with the code and CodePen below:

box.style.setProperty('font-family', 'Georgia, serif', 'important');
box.style.setProperty('font-size', '1.5em');

box.style.getPropertyPriority('font-family'); // important
op2.innerHTML = box.style.getPropertyPriority('font-size'); // ""

See the Pen Using getPropertyPriority() to get a property’s “importance” by Louis Lazaris (@impressivewebs) on CodePen.

In the first line of that code, you can see I’m using the setProperty() method, as I did before. However, notice I’ve included a third argument. The third argument is an optional string that defines whether you want the property to have the !important keyword attached to it.

After I set the property with !important, I use the getPropertyPriority() method to check that property’s priority. If you want the property to not have importance, you can omit the third argument, use the keyword undefined, or include the third argument as an empty string.

And I should emphasize here that these methods would work in conjunction with any inline styles already placed directly in the HTML on an element’s style attribute.

So if I had the following HTML:

<div class="box" style="border: solid 1px red !important;">

I could use any of the methods discussed in this section to read or otherwise manipulate that style. And it should be noted here that since I used a shorthand property for this inline style and set it to !important, all of the longhand properties that make up that shorthand will return a priority of important when using getPropertyPriority(). See the code and demo below:

// These all return "important"
box.style.getPropertyPriority('border'));
box.style.getPropertyPriority('border-top-width'));
box.style.getPropertyPriority('border-bottom-width'));
box.style.getPropertyPriority('border-color'));
box.style.getPropertyPriority('border-style'));

See the Pen Using getPropertyPriority() to check the priority of longhand properties by Louis Lazaris (@impressivewebs) on CodePen.

In the demo, even though I explicitly set only the border property in the style attribute, all the associated longhand properties that make up border will also return a value of important.

The CSSStyleSheet Interface

So far, much of what I’ve considered deals with inline styles (which often aren’t that useful) and computed styles (which are useful, but are often too specific).

A much more useful API that allows you to retrieve a stylesheet that has readable and writable values, and not just for inline styles, is the CSSStyleSheet API. The simplest way to access information from a document’s stylesheets is using the styleSheets property of the current document. This exposes the CSSStyleSheet interface.

For example, the line below uses the length property to see how many stylesheets the current document has:

document.styleSheets.length; // 1

I can reference any of the document’s stylesheets using zero-based indexing:

document.styleSheets[0];

If I log that stylesheet to my console, I can view the methods and properties available:

The CSSStyleSheet Interface in the DevTools Console

The one that will prove useful is the cssRules property. This property provides a list of all CSS rules (including declaration blocks, at-rules, media rules, etc.) contained in that stylesheet. In the following sections, I’ll detail how to utilize this API to manipulate and read styles from an external stylesheet.

Working with a Stylesheet Object

For the purpose of simplicity, let’s work with a sample stylesheet that has only a handful of rules in it. This will allow me to demonstrate how to use the CSSOM to access the different parts of a stylesheet in a similar way to accessing elements via DOM scripting.

Here is the stylesheet I’ll be working with:

* {
  box-sizing: border-box;
}

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 2em;
  line-height: 1.4;
}

main {
  width: 1024px;
  margin: 0 auto !important;
}

.component {
  float: right;
  border-left: solid 1px #444;
  margin-left: 20px;
}

@media (max-width: 800px) {
  body {
    line-height: 1.2;
  }

  .component {
    float: none;
    margin: 0;
  }
}

a:hover {
  color: lightgreen;
}

@keyframes exampleAnimation {
  from {
    color: blue;
  }
  
  20% {
    color: orange;
  }
  
  to {
    color: green;
  }
}

code {
  color: firebrick;
}

There’s a number of different things I can attempt with this example stylesheet and I’ll demonstrate a few of those here. First, I’m going to loop through all the style rules in the stylesheet and log the selector text for each one:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('p');

for (i of myRules) {
  if (i.type === 1) {
    p.innerHTML += `<c​ode>${i.selectorText}</c​ode><br>`;
  }
}

See the Pen Working with CSSStyleSheet – Logging the Selector Text by Louis Lazaris (@impressivewebs) on CodePen.

A couple of things to take note of in the above code and demo. First, I cache a reference to the cssRules object for my stylesheet. Then I loop over all the rules in that object, checking to see what type each one is.

In this case, I want rules that are type 1, which represents the STYLE_RULE constant. Other constants include IMPORT_RULE (3), MEDIA_RULE (4), KEYFRAMES_RULE (7), etc. You can view a full table of these constants in this MDN article.

When I confirm that a rule is a style rule, I print the selectorText property for each of those style rules. This will produce the following lines for the specified stylesheet:

*
body
main
.component
a:hover
code

The selectorText property is a string representation of the selector used on that rule. This is a writable property, so if I want I can change the selector for a specific rule inside my original for loop with the following code:

if (i.selectorText === 'a:hover') {
  i.selectorText = 'a:hover, a:active';
}

See the Pen Working with the CSSStyleSheet API – Changing the Selector Text by Louis Lazaris (@impressivewebs) on CodePen.

In this example, I’m looking for a selector that defines :hover styles on my links and expanding the selector to apply the same styles to elements in the :active state. Alternatively, I could use some kind of string method or even a regular expression to look for all instances of :hover, and then do something from there. But this should be enough to demonstrate how it works.

Accessing @media Rules with the CSSOM

You’ll notice my stylesheet also includes a media query rule and a keyframes at-rule block. Both of those were skipped when I searched for style rules (type 1). Let’s now find all @media rules:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('.output');

for (i of myRules) {
  if (i.type === 4) {
    for (j of i.cssRules) {
      p.innerHTML += `<c​ode>${j.selectorText}</c​ode><br>`;
    }
  }
}

Based on the given stylesheet, the above will produce:

body
.component

See the Pen Working with the CSSStyleSheet API – Accessing @media Rules by Louis Lazaris (@impressivewebs) on CodePen.

As you can see, after I loop through all the rules to see if any @media rules exist (type 4), I then loop through the cssRules object for each media rule (in this case, there’s only one) and log the selector text for each rule inside that media rule.

So the interface that’s exposed on a @media rule is similar to the interface exposed on a stylesheet. The @media rule, however, also includes a conditionText property, as shown in the following snippet and demo:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('.output');

for (i of myRules) {
  if (i.type === 4) {
    p.innerHTML += `<c​ode>${i.conditionText}</c​ode><br>`;
    // (max-width: 800px) 
  }
}

See the Pen Working with the CSSStyleSheet API – Accessing @media Rules by Louis Lazaris (@impressivewebs) on CodePen.

This code loops through all media query rules and logs the text that determines when that rule is applicable (i.e. the condition). There’s also a mediaText property that returns the same value. According to the spec, you can get or set either of these.

Accessing @keyframes Rules with the CSSOM

Now that I’ve demonstrated how to read information from a @media rule, let’s consider how to access a @keyframes rule. Here’s some code to get started:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('.output');

for (i of myRules) {
  if (i.type === 7) {
    for (j of i.cssRules) {
     p.innerHTML += `<c​ode>${j.keyText}</c​ode><br>`;
    }
  }
}

See the Pen Working with the CSSStyleSheet API – Accessing @keyframes Rules by Louis Lazaris (@impressivewebs) on CodePen.

In this example, I’m looking for rules that have a type of 7 (i.e. @keyframes rules). When one is found, I loop through all of that rule’s cssRules and log the keyText property for each. The log in this case will be:

"0%"
"20%"
"100%"

You’ll notice my original CSS uses from and to as the first and last keyframes, but the keyText property computes these to 0% and 100%. The value of keyText can also be set. In my example stylesheet, I could hard code it like this:

// Read the current value (0%)
document.styleSheets[0].cssRules[6].cssRules[0].keyText;

// Change the value to 10%
document.styleSheets[0].cssRules[6].cssRules[0].keyText = '10%'

// Read the new value (10%)
document.styleSheets[0].cssRules[6].cssRules[0].keyText;

See the Pen Working with the CSSStyleSheet API – Setting @keyframes Rules by Louis Lazaris (@impressivewebs) on CodePen.

Using this, we can dynamically alter an animation’s keyframes in the flow of a web app or possibly in response to a user action.

Another property available when accessing a @keyframes rule is name:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('.output');

for (i of myRules) {
  if (i.type === 7) {
    p.innerHTML += `<c​ode>${i.name}</c​ode><br>`;
  }
}

See the Pen Working with the CSSStyleSheet API – Getting the name of a @keyframes rule by Louis Lazaris (@impressivewebs) on CodePen.

Recall that in the CSS, the @keyframes rule looks like this:

@keyframes exampleAnimation {
  from {
    color: blue;
  }
  
  20% {
    color: orange;
  }
  
  to {
    color: green;
  }
}

Thus, the name property allows me to read the custom name chosen for that @keyframes rule. This is the same name that would be used in the animation-name property when enabling the animation on a specific element.

One final thing I’ll mention here is the ability to grab specific styles that are inside a single keyframe. Here’s some example code with a demo:

let myRules = document.styleSheets[0].cssRules,
    p = document.querySelector('.output');

for (i of myRules) {
  if (i.type === 7) {
    for (j of i.cssRules) {
      p.innerHTML += `<c​ode>${j.style.color}</c​ode><br>`;
    }
  }
}

See the Pen Working with the CSSStyleSheet API – Accessing Property Values inside @keyframes Rules by Louis Lazaris (@impressivewebs) on CodePen.

In this example, after I find the @keyframes rule, I loop through each of the rules in the keyframe (e.g. the “from” rule, the “20%” rule, etc). Then, within each of those rules, I access an individual style property. In this case, since I know color is the only property defined for each, I’m merely logging out the color values.

The main takeaway in this instance is the use of the style property, or object. Earlier I showed how this property can be used to access inline styles. But in this case, I’m using it to access the individual properties inside of a single keyframe.

You can probably see how this opens up some possibilities. This allows you to modify an individual keyframe’s properties on the fly, which could happen as a result of some user action or something else taking place in an app or possibly a web-based game.

Adding and Removing CSS Declarations

The CSSStyleSheet interface has access to two methods that allow you to add or remove an entire rule from a stylesheet. The methods are: insertRule() and deleteRule(). Let’s see both of them in action manipulating our example stylesheet:

let myStylesheet = document.styleSheets[0];
console.log(myStylesheet.cssRules.length); // 8

document.styleSheets[0].insertRule('article { line-height: 1.5; font-size: 1.5em; }', myStylesheet.cssRules.length);
console.log(document.styleSheets[0].cssRules.length); // 9

See the Pen Working with the CSSStyleSheet API – Inserting Rules by Louis Lazaris (@impressivewebs) on CodePen.

In this case, I’m logging the length of the cssRules property (showing that the stylesheet originally has 8 rules in it), then I add the following CSS as an individual rule using the insertRule() method:

article {
  line-height: 1.5;
  font-size: 1.5em;
}

I log the length of the cssRules property again to confirm that the rule was added.

The insertRule() method takes a string as the first parameter (which is mandatory), comprising the full style rule that you want to insert (including selector, curly braces, etc). If you’re inserting an at-rule, then the full at-rule, including the individual rules nested inside the at-rule can be included in this string.

The second argument is optional. This is an integer that represents the position, or index, where you want the rule inserted. If this isn’t included, it defaults to 0 (meaning the rule will be inserted at the beginning of the rules collection). If the index happens to be larger than the length of the rules object, it will throw an error.

The deleteRule() method is much simpler to use:

let myStylesheet = document.styleSheets[0];
console.log(myStylesheet.cssRules.length); // 8

myStylesheet.deleteRule(3);
console.log(myStylesheet.cssRules.length); // 7

See the Pen Working with the CSSStyleSheet API – Deleting Rules by Louis Lazaris (@impressivewebs) on CodePen.

In this case, the method accepts a single argument that represents the index of the rule I want to remove.

With either method, because of zero-based indexing, the selected index passed in as an argument has to be less than the length of the cssRules object, otherwise it will throw an error.

Revisiting the CSSStyleDeclaration API

Earlier I explained how to access individual properties and values declared as inline styles. This was done via element.style, exposing the CSSStyleDeclaration interface.

The CSSStyleDeclaration API, however, can also be exposed on an individual style rule as a subset of the CSSStyleSheet API. I already alluded to this when I showed you how to access properties inside a @keyframes rule. To understand how this works, compare the following two code snippets:

<div style="color: lightblue; width: 100px; font-size: 1.3em !important;"></div>
.box {
  color: lightblue;
  width: 100px;
  font-size: 1.3em !important;
}

The first example is a set of inline styles that can be accessed as follows:

document.querySelector('div').style

This exposes the CSSStyleDeclaration API, which is what allows me to do stuff like element.style.color, element.style.width, etc.

But I can expose the exact same API on an individual style rule in an external stylesheet. This means I’m combining my use of the style property with the CSSStyleSheet interface.

So the CSS in the second example above, which uses the exact same styles as the inline version, can be accessed like this:

document.styleSheets[0].cssRules[0].style

This opens up a single CSSStyleDeclaration object on the one style rule in the stylesheet. If there were multiple style rules, each could be accessed using cssRules[1], cssRules[2], cssRules[3], and so on.

So within an external stylesheet, inside of a single style rule that is of type 1, I have access to all the methods and properties mentioned earlier. This includes setProperty(), getPropertyValue(), item(), removeProperty(), and getPropertyPriority(). In addition to this, those same features are available on an individual style rule inside of a @keyframes or @media rule.

Here’s a code snippet and demo that demonstrates how these methods would be used on an individual style rule in our sample stylesheet:

// Grab the style rules for the body and main elements
let myBodyRule = document.styleSheets[0].cssRules[1].style,
    myMainRule = document.styleSheets[0].cssRules[2].style;

// Set the bg color on the body
myBodyRule.setProperty('background-color', 'peachpuff');

// Get the font size of the body
myBodyRule.getPropertyValue('font-size');

// Get the 5th item in the body's style rule
myBodyRule.item(5);

// Log the current length of the body style rule (8)
myBodyRule.length;

// Remove the line height
myBodyRule.removeProperty('line-height');

// log the length again (7)
myBodyRule.length;

// Check priority of font-family (empty string)
myBodyRule.getPropertyPriority('font-family');

// Check priority of margin in the "main" style rule (!important)
myMainRule.getPropertyPriority('margin');

See the Pen Working with the style object of an individual style rule in an external Stylesheet by Louis Lazaris (@impressivewebs) on CodePen.

The CSS Typed Object Model… The Future?

After everything I’ve considered in this article, it would seem odd that I’d have to break the news that it’s possible that one day the CSSOM as we know it will be mostly obsolete.

That’s because of something called the CSS Typed OM which is part of the Houdini Project. Although some people have noted that the new Typed OM is more verbose compared to the current CSSOM, the benefits, as outlined in this article by Eric Bidelman, include:

  • Fewer bugs
  • Arithmetic operations and unit conversion
  • Better performance
  • Error handling
  • CSS property names are always strings

For full details on those features and a glimpse into the syntax, be sure to check out the full article.

As of this writing, CSS Typed OM is supported only in Chrome. You can see the progress of browser support in this document.

Final Words

Manipulating stylesheets via JavaScript certainly isn’t something you’re going to do in every project. And some of the complex interactions made possible with the methods and properties I’ve introduced here have some very specific use cases.

If you’ve built some kind of tool that uses any of these APIs I’d love to hear about it. My research has only scratched the surface of what’s possible, but I’d love to see how any of this can be used in real-world examples.

I’ve put all the demos from this article into a CodePen collection, so you can feel free to mess around with those as you like.

The post An Introduction and Guide to the CSS Object Model (CSSOM) appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Google Labs Web Components

December 10th, 2018 No comments

I think it’s kinda cool to see Google dropping repos of interesting web components. It demonstrates the possibilities of cool new web features and allows them to ship them in a way that’s compatible with entirely web standards.

Here’s one:

I wanted to give it a try, so I linked up their example two-up-min.js script in a Pen and used the element by itself to see how it works. They expose the component’s styling with custom properties, which I’d say is a darn nice use case for those.

<p data-height="455" data-theme-id="1" data-slug-hash="YRowgW" data-default-tab="html,result" data-user="chriscoyier" data-pen-title="”>See the Pen <two-up&rt; by Chris Coyier (@chriscoyier) on CodePen.

The post Google Labs Web Components appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

What do you name color variables?

December 7th, 2018 No comments

What naming scheme do you use for color variables?
Have you succeeded at writing CSS that uses color variables in a manner agnostic to the colors they represent?
I’ve tried all of the following, and I have yet to succeed at writing CSS that works well with any color scheme. ??

— Lea Verou (@LeaVerou) October 14, 2018

I remember the very first time I tried Sass on a project. The first thing I wanted to do was variablize my colors. From my naming-things-in-HTML skillz, I knew to avoid classes like .header-blue-left-bottom because the color and position of that element might change. It’s better for the to reflect it what it is than what it looks like.

So, I tried to make my colors semantic, in a sense — what they represent not what they literally are:

$mainBrandColor: #F060D6;
$secondaryFocus: #4C9FEB;
$fadedHighlight: #F1F3F4;

But I found that I absolutely never remembered them and had to constantly refer to where I defined them in order to use them. Later, in a “screw it” moment, I named colors more like…

$orange: #F060D6;
$red: #BB532E;
$blue: #4C9FEB;

$gray-1: #eee;
$gray-2: #ccc;
$gray-3: #555;

I found that to be much more intuitive with little if any negative side effects. After all, this isn’t crossing the HTML-CSS boundary here; this is all within CSS and developer-only-facing, which puts more of a narrow scope on the problem.

In a similar fashion, I’ve tried keeping colors within a Sass map, like:

$colors: (
  light: #ccc,
  dark: #333
);

But the only vague goal there was to clean up the global namespace, which probably isn’t worth the hassle of needing to map-get all the time. Namespacing like $-c-orange is probably an easier approach if you need to do anything at all.

I’ve largely stuck with that just-use-color-names approach today in Sass. As the shift toward CSS custom properties happens, I think having a --c-orange and --c-gray-5 is similarly appropriate.

:root {
  -c-orange: #F060D6;
  -c-red: #BB532E;
  -c-blue: #4C9FEB;

  -c-gray-1: #eee;
  -c-gray-2: #ccc;
  -c-gray-3: #555;
}

You could get a little more specific with those names with staying abstract, like Marcus Ortense says:

$color-primary:
$color-primary-dark:
$color-primary-light: 

And variations on each base like Mike Street says:

$primary:
$primaryLight: 
$primaryDark:

$secondary:
$secondaryLight:
$secondaryDark:

$neutralDarker:
$neutrayDark:
$neutral:
$neutralLight:
$neutralLighter: 
$neutralLightest: 

Silvestar Bistrovi? recently wrote about using abstract Greek numbering:

$color-alpha: #12e09f;
$color-beta: #e01258;
$color-gamma: #f5f5f5;
$color-psi: #1f1f1f;
$color-omega: #fff;

I’ve used that kind of thing for media query breakpoints before, as the numbering seems to make sense there (i.e. low numbers are smaller screens, big numbers are bigger screens). I could also see that being nice for tints or shades of the same color, but then why not regular numbers?

Another approach I’ve often seen is to combine named colors with abstracted names. Geoff does that and John Carroll lists that here:

$color-danube: #668DD1;
$color-cornflower: $6195ED;
$color-east-bay: $3A4D6E;

// theme1.scss
$color-alpha: $color-danube;
$color-bravo: $color-cornflower;
$color-charlie: $color-east-bay;

// theme2.scss
$color-alpha: $color-cornflower;
$color-bravo: $color-danube;
$color-charlie: $color-east-bay;

That can get as verbose as you need it to, even adding variations as you call from the palette.

$table-row-background: lighten($color-background, 10%);

Stuart Robson even gets a bit BEM-y with the names, including the namespace:

$ns-color__blue—dark: rgb(25,25,112); 
$ns-brand__color—primary: $ns-color__blue—dark;

// component.scss
$ns-component__color—text: $ns-brand__color—primary;

Material Design uses values that are similar to font-weight! That means you’d end up with something like a base range plus alternates:

$light-green-100:
$light-green-200:
$light-green-300:
// etc
$light-green-900:
$light-green-A200:
$light-green-A400:

$deep-purple-100:
$deep-purple-200:
$deep-purple-300:
// etc
$deep-purple-A900:

How might you pick names for colors? You might get a kick out of what to call a sunny yellow versus a sunflower yellow, or you might just want some help. Here’s one project for that, and here’s another:

See the Pen Color Namer by Maneesh (@maneeshc) on CodePen.

There is even a Sublime Text plugin for converting them (to whatever syntax you want):

And since we’re on the topic of naming:

The post What do you name color variables? appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Accessible SVG Icons With Inline Sprites

December 7th, 2018 No comments

This is a great look at accessible SVG markup patterns by Marco Hengstenberg. Here’s the ideal example:

<button type="button">
  Menu
  <svg class="svg-icon"
     role="img"
     height="10"
     width="10"
     viewBox="0 0 10 10"
     aria-hidden="true"
     focusable="false">
     <path d="m1 7h8v2h-8zm0-3h8v2h-8zm0-3h8v2h-8z"/>
    </svg>
</button>

Notes:

  • It’s not the itself that is interactive — it’s wrapped in a
  • The .svg-icon class has some nice trickery, like em-based sizing to match the size of the text it’s next to, and currentColor to match the color.
  • Since real text is next to it, the icon can be safely ignored via aria-hidden="true". If you need an icon-only button, you can wrap that text in an accessibily-friendly .visually-hidden class.
  • The focusable="false" attribute solves an IE 11 bug.

Plus a handy Pen to reference all the patterns.

Direct Link to ArticlePermalink

The post Accessible SVG Icons With Inline Sprites appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

WordPress 5.0 Is Here (and Yes, So Is Gutenberg)

December 7th, 2018 No comments

WordPess 5.0 (codenamed “Bebo”) is officially out and prowling among the servers.

This, then, is when we find out how well Gutenberg works out. And make no mistake, whatever they’ve done under the hood, this release is about Gutenberg, both technically and in the public perception. It’s almost the only thing they talk about in their own blog post about this release.

?

Gutenberg

Automattic has set out to redefine the content editing experience in the CMS that powers at least a third of the Internet, and that is exactly what they’ve done. I think it’s for the better; others…not so much; still others think it’s a good idea that needs more development time.

Personally, I think a lot of that negative perception comes from earlier development builds. Those were builds that I didn’t use much because, well, they weren’t finished. I’d be surprised, honestly, if it was bug-free even now. That’s just not how software development seems to work these days. I’ve got my fingers crossed that it’s finished enough.

I’ve got my fingers crossed that it’s finished enough

I mean hey, I might be used to wrangling with unruly software, but someone who just wants to post on their blog already might not be as forgiving. The point is, whether any of us are ready or not, it’s here, and I personally quite like it.

One of the features that I find quite useful is the collection of default embedding blocks that allow you to easily embed content from a wide variety of sources. The classic editor had a bit of this functionality, but the current system gives you a proper idea of what you can and can’t embed by default, and I’m pretty sure some of the options were previously only available through third-party plugins. [Figure 1]

It might be a bit late for that Tumblr Embed Block, though. Ahem.

Another feature I like are contextual icons that appear on the upper-right of any new block, allowing you to select recently-used blocks quickly. That could come in handy when editing a longer document. [Figure 2]

For those of you who want to wait for Automattic to develop Gutenberg a little further, they have a Classic Editor plugin, as promised. The word is they’ll be supporting this plugin until 2021. Incidentally, it has a rating of 4.9 according to wordpress.org’s own rating system, and over 600,000 active installations at the time of this writing.

All plugins that previously made changes and additions to the classic editor should still work with this plugin, so it’s a viable option for those who want to play it safe.

Themes and Such

Twenty-Nineteen made it into the final release. Since that wasn’t always guaranteed, I’m glad it got finished up in time. They needed a way to properly showcase Gutenberg’s capabilities with this release, and now they have one. For a preview of said theme, as well as my thoughts on it, see Previewing the WordPress Twenty-Nineteen Theme. (Side note: all themes from Twenty-Ten to Twenty-Seventeen have been updated to support Gutenberg.)

For designers and developers, theme creation just got a bit easier and a bit more complicated at the same time. On the one hand, it is now possible to handle a lot of content-related layout within the CMS itself, which will save time when developing custom theme options. It gives users more control over the general flow of content, giving them more creative opportunities, and takes some work off your plate.

On the other hand, you need to make sure you have styles ready for all of the default content blocks available in every theme you make. This is not terribly difficult, and it shouldn’t take too long to develop a library of custom styles that can be adjusted to every theme, but it’s something to consider.

Additionally, most of the third-party block plugins I’ve seen are not style-agnostic, though most have multiple style options to choose from. I can see third-party blocks being something of a double-edged sword.

WordPress Support Changes

One last tidbit that was actually announced on December 3rd is a new support platform for WordPress. It’s called “HelpHub”, and it’s located at wordpress.org/support. They’re still migrating content from the old WordPress Codex, so that’s still there for now, but this is the new official help center.

It seems to be pretty heavily integrated with the support forums, so it seems like the general plan was to make help easier to find by putting it all (more or less) in one place. I’d call this an overall improvement.

My Opinion

On my own personal projects, the update installed flawlessly. I can’t report much on potential bugs, as yet, because this release just happened, but so far I like it quite a bit. I honestly like the new editor, and the new direction WordPress is heading in. There’s a lot of potential here. Whether or not you think Gutenberg is ready for release, as I do, the thing to realize is that Gutenberg is only the next step in a long journey.

Automattic has been working long and hard to transform WordPress from a pure-blog CMS into something like a framework or data platform, all without sacrificing usability, or too much in the way of backwards compatibility. The blog you could install in five minutes has more or less become the ecosystem you can install in five minutes, and then build any site you want.

It’s not perfect, and it’s not done yet, but this release is a giant step toward something we’ve never seen before. I’m genuinely excited to find out what it’ll be.

Add Realistic Chalk and Sketch Lettering Effects with Sketch’it – only $5!

Source

Categories: Designing, Others Tags:

Compound Components in React Using the Context API

December 7th, 2018 No comments
Form is the provider with state, Form Panel is the consumer receiving state, Panel displays the panel based on the state, and Signup and Login render the form views in the Panel.

Compound components in React allow you to create components with some form of connected state that’s managed amongst themselves. A good example is the Form component in Semantic UI React.

To see how we can implement compound components in a real-life React application, we’ll build a compound (multi-part) form for login and sign up. The state will be saved in the form component and we’ll put React’s Context AP to use to pass that state and the method from the Context Provider to the component that needs them. The component that needs them? It will become a subscriber to Context Consumers.

Here’s what we’re building:

See the Pen React Compound Component by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Here’s a rough outline that shows how the following steps fit together:

Form is the provider with state, Form Panel is the consumer receiving state, Panel displays the panel based on the state, and Signup and Login render the form views in the Panel.

Before treading any further, you may want to brush up on the React Context API if you haven’t already. Neal Fennimore demonstrates the concept in this post and my primer on it is worth checking out as well.

Step 1: Creating context

First, let’s initialize a new context using the React Context API.

const FormContext = React.createContext({});
const FormProvider = FormContext.Provider;
const FormConsumer = FormContext.Consumer;

The provider, FormProvider, will hold the application state, making it available to components that subscribe to FormConsumer.

Step 2: Implement provider

One panel contains the form to log in and the other contains the form to sign up. In the provider, we want to declare the state, which determines the active panel, i.e. the form currently in display. We’ll also create a method to switch from one panel to another when a heading is clicked.

class Form extends React.Component {
  state = {
    activePanel: "login"
  };

  render() {
    return (
      <React.Fragment>
        <FormProvider
          value={{
            activePanel: this.state.activePanel,
            actions: {
              handlePanelSwitch: newPanel => {
                this.setState({
                  activePanel: newPanel
                });
              }
            }
          }}
        >
          {this.props.children}
        </FormProvider>
      </React.Fragment>
    );
  }
}

By default, the login panel will be shown to the user. When the signup panel is clicked, we want to make it the active panel by setting the state of activePanel to signup using the method handlePanelSwitch().

Step 3: Implement Consumers

We’ll use FormConsumer to make context available to the components that subscribe to it. That means the FormPanel component that handles displaying panels will look like this:

const FormPanel = props => {
  return (
    <FormConsumer>
      {({ activePanel }) =>
        activePanel === props.isActive ? props.children : null
      }
    </FormConsumer>
  );
};

And the Panel component will look like this:

const Panel = props => (
  <FormConsumer>
    {({ actions }) => {
      return (
        <div onClick={() => actions.switchPanel(props.id)}>
          {props.children}
        </div>
      );
    }}
  </FormConsumer>
);

To understand what is happening, let’s understand the approach here. The login and signup panels will have unique IDs that get passed via props to the Panel component. When a panel is selected, we get the ID and and use it to set activePanel to swap forms. The FormPanel component also receives the name of the panel via the isActive prop and we then check to see if the returned value is true. If it is, then the panel is rendered!

To get the full context, here is how the App component looks:

const App = () => {
  return (
    <div className="form-wrap">
      <Form>
        <div className="tabs">
          <Panel id="login">
            <h2 className="login-tab">Login</h2>
          </Panel>
          <Panel id="signup">
            <h2 className="signup-tab">Sign Up</h2>
          </Panel>
        </div>

        <FormPanel isActive="login">
          <Login />
        </FormPanel>

        <FormPanel isActive="signup">
          <SignUp />
        </FormPanel>
      </Form>
    </div>
  );
};

You can see how the components are composed when activePanel matches isActive (which is supposed to return true). The component is rendered under those conditions.

With that done, the Login component looks like this:

const Login = () => {
  return (
    <React.Fragment>
      <div id="login-tab-content">
        <form className="login-form" action="" method="post">
          <input
            type="text"
            className="input"
            id="user_login"
            placeholder="Email or Username"
          />
          <input
            type="password"
            className="input"
            id="user_pass"
            placeholder="Password"
          />
          <input type="checkbox" className="checkbox" id="remember_me" />
          <label htmlFor="remember_me">Remember me</label>

          <input type="submit" className="button" value="Login" />
        </form>
      </div>
    </React.Fragment>
  );
};

And the SignUp component:

const SignUp = () => {
  return (
    <React.Fragment>
      <div id="signup-tab-content" className="active tabs-content">
        <form className="signup-form" action="" method="post">
          <input
            type="email"
            className="input"
            id="user_email"
            placeholder="Email"
          />
          <input
            type="text"
            className="input"
            id="user_name"
            placeholder="Username"
          />
          <input
            type="password"
            className="input"
            id="user_pass"
            placeholder="Password"
          />
          <input type="submit" className="button" value="Sign Up" />
        </form>
      </div>
    </React.Fragment>
  );
};

Get it? Got it? Good!

You can use this pattern anytime you have components in your React application that need to share implicit state. You can also build compound components using React.cloneElement().

References

The post Compound Components in React Using the Context API appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Edge’s Announcements

December 6th, 2018 No comments

The public-consumption blog post:

Ultimately, we want to make the web experience better for many different audiences. People using Microsoft Edge (and potentially other browsers) will experience improved compatibility with all web sites, while getting the best-possible battery life and hardware integration on all kinds of Windows devices. Web developers will have a less-fragmented web platform to test their sites against, ensuring that there are fewer problems and increased satisfaction for users of their sites; and because we’ll continue to provide the Microsoft Edge service-driven understanding of legacy IE-only sites, Corporate IT will have improved compatibility for both old and new web apps in the browser that comes with Windows.

For us devs:

  1. We are making this decision for the long term. We expect our engineers to learn and over time become experts in the Chromium project and grow into active and responsible members of the community. We are eager to increase our contributions to the Chromium project and will continue to maintain any contributions we make.

  2. When seeking improvements in the web platform, our default position will be to contribute. We are focused on delivering a world class browser with Microsoft Edge through its differentiated user experience features and connected services, but where new platform capabilities are concerned, we will seek a ‘rising tide that floats all boats’. We will get started with bug fixes and meaningful contributions in such areas as ARM64 support, accessibility, security, touch input and power enhancements on Windows.

  3. We recognize and will respect the architecture requirements and engineering approach that are intrinsic in web open-source projects and have made Chromium successful. There are many aspects that have governed Chromium OSS and other projects: multi-device support, multi-OS support, rigorous real-time engineering, etc. Although our company has historically had a focus on Windows PCs and we believe we can make contributions that improve browsers on Windows, we also understand that web OSS projects embrace a wide range of device-types, including Android, and that contributions must accommodate this device diversity. We will contribute in a way that is consistent with the architectural design that meets Chromium’s cross-platform and cross-device needs.

  4. We believe the evolution of the open web is best served though the standards communities, and the open web benefits from open debate from a wide variety of perspectives. We will remain deeply and vigorously engaged in the standards discussions in the context of the W3C, ECMA and the WHATWG where the perspectives of vendors developing competing browsers and the larger web community can be heard and considered.

Nothing terribly surprising here. We’re doing this. We think it’ll be good for everybody. I’m slightly surprised they didn’t attempt to answer everyone’s main worry: is the web actually better off with less engine diversity? We’ll never know I guess.

The post Edge’s Announcements appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Browser Diversity Commentary, Regarding the Edge News

December 6th, 2018 No comments

Still no word from the horse’s mouth about the reported EdgeHTML demise, but I hear that’s coming later today. The blog posts are starting to roll in about the possible impact of this though.

Andre Garzia: While we Blink, we loose the Web:

Even though Opera, Beaker and Brave are all doing very good work, it is still Chrome engine behind them and that limits the amount of stuff they can build and innovate. It is like as if they were building cars, there is a lot they can do without actually changing the engine itself, and thats what the Web Browsers are becoming, everyone is working on parts of the car but all the engines are now Chrome and believe me, you don’t want all the engines to be the same, not even if they are all Gecko or if somehow we resurrect Presto, we want diversity of engines and not monoculture.

Tim Kadlec, Risking a Homogeneous Web:

I can understand the logic. Microsoft can’t put as many folks on Edge (including EdgeHTML for rendering and Chakra for JavaScript) as Google has done with Chromium (using Blink for rendering and V8 for JavaScript), so keeping up was always going to be a challenge. Now they can contribute to the same codebase and try to focus on the user-focused features. Whether this gets people to pay more attention to their next browser or not remains to be seen, but I get the thinking behind the move.

The big concern here is we’ve lost another voice from an engine perspective.

Ferdy Christant, The State of Web Browsers:

Edge is doomed. It was doomed and its next version will be equally doomed from the start. For the simple reason that Microsoft has close to no say in how browsers get installed: on mobile as a default app, and on desktop via web services under the control of Google. Switching to Chromium makes no difference in market share, as the only way to compete now is through the browser’s UI, not via the engine. Which isn’t a competition at all, since browser UI is a commodity.

I’ll link up the official statements as they come out.

The post Browser Diversity Commentary, Regarding the Edge News appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

DRY State Switching With CSS Variables: Fallbacks and Invalid Values

December 6th, 2018 No comments
Screenshot collage. On the left, we have the wide screen scenario, with four paragraphs as the four horizontal, offset based on parity slices of a disc. The slice numbering position is either to the right or left of the actual text content, depending on parity. The text alignment also depends on parity. In the middle, we have the normal screen case. The paragraphs are now full width rectangular elements. On the right, we have the narrow screen case. The paragraph numbering is always above the actual text content in this case.

This is the second post in a two-part series that looks into the way CSS variables can be used to make the code for complex layouts and interactions less difficult to write and a lot easier to maintain. The first installment walks through various use cases where this technique applies. This post covers the use of fallbacks and invalid values to extend the technique to non-numeric values.

The strategy of using CSS Variables to drive the switching of layouts and interactions that we covered in the first post in this series comes with one major caveat: it only works with numeric values — lengths, percentages, angles, durations, frequencies, unit-less number values and so on. As a result, it can be really frustrating to know that you’re able to switch the computed values of more than ten properties with a single CSS variable, but then you need to explicitly switch the non-numeric values of properties like flex-direction or text-align from row to column or from left to right or the other way around.

One example would be the one below, where the text-align property depends on parity and the flex-direction depends on whether we are viewing the front end in the wide screen scenario or not.

Screenshot collage.

I complained about this and got a very interesting suggestion in return that makes use of CSS variable fallbacks and invalid values. It was interesting and gives us something new to work with, so let’s start with a short recap of what these are and go from there!

Fallback values

The fallback value of a CSS variable is the second and optional argument of the var() function. For example, let’s consider we have some .box elements whose background is set to a variable of --c:

.box { background: var(--c, #ccc) }

If we haven’t explicitly specified a value for the --c variable elsewhere, then the fallback value #ccc is used.

Now let’s say some of these boxes have a class of .special. Here, we can specify --c as being some kind of orange:

.special { --c: #f90 }

This way, the boxes with this .special class have an orange background, while the others use the light grey fallback.

See the Pen by thebabydino (@thebabydino) on CodePen.

There are a few things to note here.

First off, the fallback can be another CSS variable, which can have a CSS variable fallback itself and… we can fall down a really deep rabbit hole this way!

background: var(--c, var(--c0, var(--c1, var(--c2, var(--c3, var(--c4, #ccc))))))

Secondly, a comma separated list is a perfectly valid fallback value. In fact, everything specified after the first comma inside the var() function constitutes the fallback value, as seen in the example below:

background: linear-gradient(90deg, var(--stop-list, #ccc, #f90))

See the Pen by thebabydino (@thebabydino) on CodePen.

And last, but certainly not least, we can have different fallback values for the same variable used in different places, as illustrated by this example:

$highlight: #f90;

a {
  border: solid 2px var(--c, #{rgba($highlight, 0)})
  color: var(--c, #ccc);
  
  &:hover, &:focus { --c: #{$highlight} }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Invalid values

First off, I want to clarify what I mean by this. “Invalid values” is shorter and easier to remember, but what it really refers to any value that makes a declaration invalid at computed value time.

For example, consider the following piece of code:

--c: 1em;
background: var(--c)

1em is a valid length value, but this is not a valid value for the background-color property, so here this property will take its initial value (which is transparent) instead.

Putting it all together

Let’s say we have a bunch of paragraphs where we change the lightness of the color value to switch between black and white based on parity (as explained in the previous post in this series):

p {
  --i: 0;
  /* for --i: 0 (odd), the lightness is 0*100% = 0% (black)
   * for --i: 1 (even), the lightness is 1*100% = 100% (white)* /
  color: hsl(0, 0%, calc(var(--i)*100%));

  &:nth-child(2n) { --i: 1 }
}

We also want the odd paragraphs to be right-aligned, while keeping the even ones left-aligned. In order to achieve this, we introduce a --parity variable which we don’t set explicitly in the general case — only for even items. What we do set in the general case is our previous variable, --i. We set it to the value of --parity with a fallback of 0:

p {
  --i: var(--parity, 0);
  color: hsl(0, 0%, calc(var(--i)*100%));

  &:nth-child(2n) { --parity: 1 }
}

So far, this achieves exactly the same as the previous version of our code. However, if we take advantage of the fact that, we can use different fallback values in different places for the same variable, then we can also set text-align to the value of --parity using a fallback of… right!

text-align: var(--parity, right)

In the general case, where we’re not setting --parity explicitly; text-align uses the fallback right, which is a valid value, so we have right alignment. For the even items however, we’re setting --parity explicitly to 1, which is not a valid value for text-align. That means text-align reverts to its initial value, which is left.

See the Pen by thebabydino (@thebabydino) on CodePen.

Now we have right alignment for the odd items and left alignment for the even items while still putting a single CSS variable to use!

Dissecting a more complex example

Let’s consider we want to get the result below:

Screenshot. Shows a bunch of numbered cards. Odd ones have the numbering on the left, while even ones have it on the right. Odd ones are right-aligned, while even ones are left-aligned. Odd ones are shifted a bit to the right and have a bit of a clockwise rotation, while even ones are shifted and rotated by the same amounts, but in the opposite directions. All have a grey to orange gradient background, but for the odd ones, this gradient goes from left to right, while for the even ones it goes from right to left.
Numbered cards where even cards have symmetrical styles with respect to odd cards.

We create these cards with a paragraph element

for each one. We switch their box-sizing to border-box, then give them a width, a max-width, a padding and a margin. We also change the default font.

See the Pen by thebabydino (@thebabydino) on CodePen.

We’ve also added a dummy outline just to see the boundaries of these elements.

Next, let’s add the numbering using CSS counters and a :before pseudo-element:

p {
  /* same code as before */
  counter-increment: c;
  
  &:before { content: counter(c, decimal-leading-zero) }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Now, we’ll give our paragraphs a flex layout and increase the size of the numbering:

p {
  /* same code as before */
  display: flex;
  align-items: center;
  
  &:before {
    font-size: 2em;
    content: counter(c, decimal-leading-zero);
  }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Now comes the interesting part!

We set a switch --i that changes value with the parity — it’s 0 for the odd items and 1 for the even ones.

p {
  /* same code as before */
  --i: 0;
  
  &:nth-child(2n) { --i: 1 }
}

Next, we want the numbering to be on the left for the odd items and on the right for the even ones. We achieve this via the order property. The initial value for this property is 0, for both the :before pseudo-element and the paragraph’s text content. If we set this order property to 1 for the numbering (the :before pseudo-element) of the even elements, then this moves the numbering after the content.

p {
  /* same code as before */
  --i: 0;
  
  &:before {
    /* same code as before */
    /* we don't really need to set order explicitly as 0 is the initial value */
    order: 0;
  }
  
  &:nth-child(2n) {
    --i: 1;
    
    &:before { order: 1 }
  }
}

You may notice that, in this case, the order value is the same as the switch --i value, so in order to simplify things, we set the order to the switch value.

p {
  /* same code as before */
  --i: 0;
  
  &:before {
    /* same code as before */
    order: var(--i)
  }
  
  &:nth-child(2n) { --i: 1 }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Now we want a bit of spacing (let’s say $gap) in between the numbers and the paragraph text. This can be achieved with a lateral margin on the :before.

For the odd items, the item numbers are on the left, so we need a non-zero margin-right. For the even items, the item numbers are on the right, so we need a non-zero margin-left.

When the parity switch value is 0 for the odd items, the left margin is 0 = 0*$gap, while the right margin is $gap = 1*$gap = (1 - 0)*$gap.

Similarly for the even items, when the parity switch value is 1, the left margin is $gap = 1*$gap, while the right margin is 0 = 0*$gap = (1 - 1)*$gap.

The result in both cases is that margin-left is the parity switch value times the margin value ($gap), while margin-right is 1 minus the parity switch value, all multiplied with the margin value.

$gap: .75em;

p {
  /* same code as before */
  --i: 0;
  
  &:before {
    /* same code as before */
    margin: 
      0                            /* top */
      calc((1 - var(--i))*#{$gap}) /* right */
      0                            /* bottom */
      calc(var(--i)*#{$gap})       /* left */;
  }
  
  &:nth-child(2n) { --i: 1 }
}

If we use the complementary value (1 - var(--i)) in more than one place, then it’s probably best to set it to another CSS variable --j.

$gap: .75em;

p {
  /* same code as before */
  --i: 0;
  --j: calc(1 - var(--i));
  
  &:before {
    /* same code as before */
    margin: 
      0                      /* top */
      calc(var(--j)*#{$gap}) /* right */
      0                      /* bottom */
      calc(var(--i)*#{$gap}) /* left */;
  }
  
  &:nth-child(2n) { --i: 1 }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Next, we want to give these items a proper background. This is a grey to orange gradient, going from left to right (or along a 90deg angle) in the case of odd items (parity switch --i: 0) and from right to left (at a -90deg angle) in the case of even items (parity switch --i: 1).

This means the absolute value of the gradient angle is the same (90deg), only the sign is different — it’s +1 for the odd items (--i: 0) and -1 for the even items (--i: 1).

In order to switch the sign, we use the approach we covered in the first post:

/*
 * for --i: 0, we have 1 - 2*0 = 1 - 0 = +1
 * for --i: 1, we have 1 - 2*1 = 1 - 2 = -1
 */
--s: calc(1 - 2*var(--i))

This way, our code becomes:

p {
  /* same code as before */
  --i: 0;
  --s: calc(1 - 2*var(--i));
  background: linear-gradient(calc(var(--s)*90deg), #ccc, #f90);
  
  &:nth-child(2n) { --i: 1 }
}

We can also remove the dummy outline since we don’t need it at this point:

See the Pen by thebabydino (@thebabydino) on CodePen.

Next, we do something similar for the transform property.

The odd items are translated a bit to the right (in the positive direction of the x axis) and rotated a bit in the clockwise (positive) direction, while the even items are translated a bit to the left (in the negative direction of the x axis) and rotated a bit in the other (negative) direction.

The translation and rotation amounts are the same; only the signs differ.

For the odd items, the transform chain is:

translate(10%) rotate(5deg)

While for the even items, we have:

translate(-10%) rotate(-5deg)

Using our sign --s variable, the unified code is:

p {
  /* same code as before */
  --i: 0;
  --s: calc(1 - 2*var(--i));
  transform: translate(calc(var(--s)*10%)) 
             rotate(calc(var(--s)*5deg));
  
  &:nth-child(2n) { --i: 1 }
}

This is now starting to look like something!

See the Pen by thebabydino (@thebabydino) on CodePen.

The next step is to round the card corners. For the odd cards, we want the corners on the left side to be rounded to a radius of half the height. For the even items, we want the corners on the right side to be rounded to the same radius.

Given we don’t know the heights of our cards, we just use a ridiculously large value, say something like 50vh, which gets scaled down to fit due to the way border-radius works. In our case, this means scaled down to whichever is smaller between half the item height (since going vertically has both a top and bottom rounded corner on the same side) and the full item width (since going horizontally has one rounded corner; either on the left or on the right, but not on both the right and the left).

This means we want the corners on the left to have this radius ($r: 50vh) for odd items (--i: 0) and the ones on the right to have the same radius for even items (--i: 1). As a result, we do something pretty similar to the numbering margin case:

$r: 50vh;

p {
  /* same code as before */
  --i: 0;
  --j: calc(1 - var(--i));
  --r0: calc(var(--j)*#{$r});
  --r1: calc(var(--i)*#{$r});
  /* clockwise from the top left */
  border-radius: var(--r0) /* top left */
                 var(--r1) /* top right */
                 var(--r1) /* bottom right */
                 var(--r0) /* bottom left */;
  
  &:nth-child(2n) { --i: 1 }
}

See the Pen by thebabydino (@thebabydino) on CodePen.

Now comes the truly interesting part — text alignment! We want the text in the odd items to be aligned right, while the text in the even items is aligned left. The only problem is that text-align doesn’t take a number value so, no addition or multiplication tricks can help us here.

What can help is combining the use of fallback and invalid values for CSS variables. To do this, we introduce another parity variable --p and it’s this variable that we actually set to 1 for even items. Unlike --i before, we never set --p explicitly for the general case as we want different fallback values of this variable to be used for different properties.

As for --i, we set it to --p with a fallback value of 0. This fallback value of 0 is the value that actually gets used in the general case, since we never explicitly set --p there. For the even case, where we explicitly set --p to 1, --i becomes 1 as well.

At the same time, we set the text-align property to --p with a fallback value of right in the general case. In the even case, where we have --p explicitly set to 1, the text-align value becomes invalid (because we have set text-align to the value of --p and --p is now 1, which is not a valid value for text-align), so the text reverts to being aligned to the left.

p {
  /* same code as before */
  --i: var(--p, 0);
  text-align: var(--p, right);
  
  &:nth-child(2n) { --p: 1 }
}

This gives us the result we’ve been after:

See the Pen by thebabydino (@thebabydino) on CodePen.

Handling responsiveness

While our cards example looks great on wider screens, the same can’t be said when shrink things down.

Screenshot collage. Since the width of the cards depends on the viewport width, the viewport may get too narrow to allow for displaying the numbering and the paragraph text side by side and the right one of the two overflows in this case.
The wide screen result (left) vs. the narrow screen result (right)

In order to fix this, we introduce two more custom properties, --wide and --k to switch between the wide and narrow cases. We set --k to --wide with a fallback value of 0 in the general case and then set --wide to 1 if the viewport width is anything 340px and up.

p {
  /* same code as before */
  --k: var(--wide, 0);
  
  @media (min-width: 340px) { --wide: 1 }
}

Since we only want our items to be transformed and have rounded corners in the wide case, we multiply the translation, rotation and radius values by --k (which is 0, unless the viewport is wide, which switches its value to 1).

p {
  /* same code as before */
  --k: var(--wide, 0);
  --r0: calc(var(--k)*var(--j)*#{$r});
  --r1: calc(var(--k)*var(--i)*#{$r});
  border-radius: var(--r0) /* top left */
                 var(--r1) /* top right */
                 var(--r1) /* bottom right */
                 var(--r0) /* bottom left */;
  transform: translate(calc(var(--k)*var(--s)*10%)) 
             rotate(calc(var(--k)*var(--s)*5deg));

  @media (min-width: 340px) { --wide: 1 }
}

This is slightly better, but our content still overflows in narrow viewports. We can fix this by only placing the numbering (the :before pseudo-element) on the left or right side only in the wide case then moving it above the card in the narrow case.

In order to do this, we multiply both its order and its lateral margin values by --k (which is 1 in the wide case and 0 otherwise).

We also set flex-direction to --wide with a fallback value of column.

This means the flex-direction value is column in the general case (since we haven’t set --wide explicitly elsewhere). However, if the viewport is wide (min-width: 340px), then our --wide variable gets set to 1. But 1 is an invalid value for flex-direction, so this property reverts back to its initial value of row.

p {
  /* same code as before */
  --k: var(--wide, 0);
  flex-direction: var(--wide, column);
  
  &:before {
    /* same code as before */
    order: calc(var(--k)*var(--i));
    margin: 
      0                               /* top */
      calc(var(--k)*var(--j)*#{$gap}) /* right */
      0                               /* bottom */
      calc(var(--k)*var(--i)*#{$gap}) /* left */;
  }
  
  @media (min-width: 340px) { --wide: 1 }
}

Coupled with setting a min-width of 160px on the body, we’ve now eliminated the overflow issue:


Responsive cards, no overflow (live demo).

One more thing we can do is tweak the font-size so that it also depends on --k:

p {
  /* same code as before */
  --k: var(--wide, 0);
  font: 900 calc(var(--k)*.5em + .75em) cursive;

  @media (min-width: 340px) { --wide: 1 }
}

And that’s it, our demo is now nicely responsive!


Responsive cards, font smaller for narrow screens and with no overflow (live demo).

A few more quick examples!

Let’s look at a few more demos that use the same technique, but quickly without building them from scratch. We’ll merely go through the basic ideas behind them.

Disc slices


Sliced disc (live demo).

Just like the cards example we completed together, we can use a :before pseudo-element for the numbering and a flex layout on the paragraphs. The sliced disc effect is achieved using clip-path.

The paragraph elements themselves — the horizontal offsets, the position and intensity of the radial-gradient() creating the shadow effect, the direction of the linear-gradient() and the saturation of its stops, the color and the text alignment — all depend on the --parity variable.

p {
  /* other styles not relevant here */
  --p: var(--parity, 1);
  --q: calc(1 - var(--p));
  --s: calc(1 - 2*var(--p)); /* sign depending on parity */
  transform: translate((calc(var(--i)*var(--s)*#{-$x})));
  background: 
    radial-gradient(at calc(var(--q)*100%) 0, 
      rgba(0, 0, 0, calc(.5 + var(--p)*.5)), transparent 63%) 
      calc(var(--q)*100%) 0/ 65% 65% no-repeat, 
    linear-gradient(calc(var(--s)*-90deg), 
      hsl(23, calc(var(--q)*98%), calc(27% + var(--q)*20%)), 
      hsl(44, calc(var(--q)*92%), 52%));
  color: HSL(0, 0%, calc(var(--p)*100%));
  text-align: var(--parity, right);
	
  &:nth-child(odd) { --parity: 0 }
}

For the numbering (the :before pseudo-elements of the paragraphs), we have that both the margin and the order depend on the --parity in the exact same way as the cards example.

If the viewport width is smaller than the disc diameter $d plus twice the horizontal slice offset in absolute value $x, then we’re not in the --wide case anymore. This affects the width, padding and margin of our paragraphs, as well as their horizontal offset and their shape (because we don’t clip them to get the sliced disc effect at that point).

body {
  /* other styles not relevant here */
  --i: var(--wide, 1);
  --j: calc(1 - var(--i));
	
  @media (max-width: $d + 2*$x) { --wide: 0 }
}

p {
  /* other styles not relevant here */
  margin: calc(var(--j)*.25em) 0;
  padding: 
    calc(var(--i)*#{.5*$r}/var(--n) + var(--j)*5vw) /* vertical */
    calc(var(--i)*#{.5*$r} + var(--j)*2vw) /* horizontal */;
  width: calc(var(--i)*#{$d} /* wide */ + 
              var(--j)*100% /* not wide */);
  transform: translate((calc(var(--i)*var(--s)*#{-$x})));
  clip-path: 
    var(--wide, 
        
      /* fallback, used in the wide case only */
      circle($r at 50% calc((.5*var(--n) - var(--idx))*#{$d}/var(--n))));
}

We’re in the narrow case below 270px and have a flex-direction of column on our paragraphs. We also zero out both the lateral margins and the order for the numbering.

body {
  /* other styles not relevant here */
  --k: calc(1 - var(--narr, 1));
	
  @media (min-width: 270px) { --narr: 0 }
}

p {
  /* other styles not relevant here */
  flex-direction: var(--narr, column);

  &:before {
    /* other styles not relevant here */
    margin: 
      0                             /* top */
      calc(var(--k)*var(--q)*.25em) /* right */
      0                             /* bottom */
      calc(var(--k)*var(--p)*.25em) /* left */;
    order: calc(var(--k)*var(--p));
  }
}

Four-step infographic

Screenshot collage. On the left, there's the wide screen scenario. In the middle, there's the normal screen scenario. On the right, there's the narrow screen scenario.
A four-step infographic (live demo).

This works pretty much the same as the previous two examples. We have a flex layout on our paragraphs using a column direction in the narrow case. We also have a smaller font-size in that same case:

body {
  /* other styles not relevant here */
  --k: var(--narr, 1);
  
  @media (min-width: 400px) { --narr: 0 }
}

p {
  /* other styles not relevant here */
  flex-direction: var(--narr, column);
  font-size: calc((1.25 - .375*var(--k))*1em);
}

The parity determines each paragraph’s text alignment, which lateral border gets a non-zero value, and the position and direction of the border gradient. Both the parity and whether we’re in the wide screen case or not determine the lateral margins and paddings.

body {
  /* other styles not relevant here */
  --i: var(--wide, 1);
  --j: calc(1 - var(--i));
  
  @media (max-width: $bar-w + .5*$bar-h) { --wide: 0 }
}

p {
  /* other styles not relevant here */
  margin: 
    .5em                                 /* top */
    calc(var(--i)*var(--p)*#{.5*$bar-h}) /* right */
    0                                    /* bottom */
    calc(var(--i)*var(--q)*#{.5*$bar-h}) /* left */;
  border-width: 
    0                        /* top */
    calc(var(--q)*#{$bar-b}) /* right */
    0                        /* bottom */
    calc(var(--p)*#{$bar-b}) /* left */;
  padding: 
    $bar-p                                         /* top */
    calc((var(--j) + var(--i)*var(--q))*#{$bar-p}) /* right */
    $bar-p                                         /* bottom */
    calc((var(--j) + var(--i)*var(--p))*#{$bar-p}) /* left */;
  background: 
    linear-gradient(#fcfcfc, gainsboro) padding-box, 
    linear-gradient(calc(var(--s)*90deg), var(--c0), var(--c1)) 
      calc(var(--q)*100%) /* background-position */ / 
      #{$bar-b} 100% /* background-size */;
  text-align: var(--parity, right);
}

The icon is created using the :before pseudo-element, and its order depends on the parity, but only if we’re not in the narrow screen scenario — in which case it’s always before the actual text content of the paragraph. Its lateral margin depends both on the parity and whether we are in the wide screen case or not. The big-valued component that positions it half out of its parent paragraph is only present in the wide screen case. The font-size also depends on whether we’re in the narrow screen case or not (and this influences its em dimensions and padding).

order: calc((1 - var(--k))*var(--p));
margin: 
  0                                                          /* top */
  calc(var(--i)*var(--p)*#{-.5*$ico-d} + var(--q)*#{$bar-p}) /* right */
  0                                                          /* bottom */
  calc(var(--i)*var(--q)*#{-.5*$ico-d} + var(--p)*#{$bar-p}) /* left */;
font-size: calc(#{$ico-s}/(1 + var(--k)));

The ring is created using an absolutely positioned :after pseudo-element (and its placement depends on parity), but only for the wide screen case.

content: var(--wide, '');

The two-dimension case

Screenshot collage. On the left, we have the wide screen scenario. Each article is laid out as a 2x2 grid, with the numbering occupying an entire column, either on the right for odd items or on the left for even items. The heading and the actual text occupy the other column. In the middle, we have the normal screen case. Here, we also have a 2x2 grid, but the numbering occupies only the top row on the same column as before, while the actual text content now spans both columns on the second row. On the right, we have the narrow screen case. In this case, we don't have a grid anymore, the numbering, the heading and the actual text are one under the other for each article.
Screenshot collage (live demo, no Edge support due to CSS variable and calc() bugs).

Here we have a bunch of article elements, each containing a heading. Let’s check out the most interesting aspects of how this responsive layout works!

On each article, we have a two-dimensional layout (grid) — but only if we’re not in the narrow screen scenario (--narr: 1), in which case we fall back on the normal document flow with the numbering created using a :before pseudo-element, followed by the heading, followed by the actual text. In this situation, we also add vertical padding on the heading since we don’t have the grid gaps anymore and we don’t want things to get too crammed.

html {
  --k: var(--narr, 0);
	
  @media (max-width: 250px) { --narr: 1 }
}

article {
  /* other styles irrelevant here */
  display: var(--narr, grid);
}

h3 {
  /* other styles irrelevant here */
  padding: calc(var(--k)*#{$hd3-p-narr}) 0;
}

For the grid, we create two columns of widths depending both on parity and on whether we’re in the wide screen scenario. We make the numbering (the :before pseudo-element) span two rows in the wide screen case, either on the second column or the first, depending on the parity. If we’re not in the wide screen case, then the paragraph spans both columns on the second row.

We set the grid-auto-flow to column dense in the wide screen scenario, letting it revert to the initial value of row otherwise. Since our article elements are wider than the combined widths of the columns and the column gap between them, we use place-content to position the actual grid columns inside at the right or left end depending on parity.

Finally, we place the heading at the end or start of the column, depending on parity, and we as well as the paragraph’s text alignment if we’re in the wide screen scenario.

$col-1-wide: calc(var(--q)*#{$col-a-wide} + var(--p)*#{$col-b-wide});
$col-2-wide: calc(var(--p)*#{$col-a-wide} + var(--q)*#{$col-b-wide});

$col-1-norm: calc(var(--q)*#{$col-a-norm} + var(--p)*#{$col-b-norm});
$col-2-norm: calc(var(--p)*#{$col-a-norm} + var(--q)*#{$col-b-norm});

$col-1: calc(var(--i)*#{$col-1-wide} + var(--j)*#{$col-1-norm});
$col-2: calc(var(--i)*#{$col-2-wide} + var(--j)*#{$col-2-norm});

html {
  --i: var(--wide, 1);
  --j: calc(1 - var(--i));
	
  @media (max-width: $art-w-wide) { --wide: 0 }
}

article {
  /* other styles irrelevant here */
  --p: var(--parity, 1);
  --q: calc(1 - var(--p));
  grid-template-columns: #{$col-1} #{$col-2};
  grid-auto-flow: var(--wide, dense column);
  place-content: var(--parity, center end);
  
  &:before {
    /* other styles irrelevant here */
    grid-row: 1/ span calc(1 + var(--i));
    grid-column: calc(1 + var(--p))/ span 1;
  }
  
  &:nth-child(odd) { --parity: 0 }
}

h3 {
  /* other styles irrelevant here */
  justify-self: var(--parity, self-end);
}

p {
  grid-column-end: span calc(1 + var(--j));
  text-align: var(--wide, var(--parity, right));
}

We also have numerical values such as grid gaps, border radii, paddings, font-sizes, gradient directions, rotation and translation directions depending on the parity and/or whether we’re in the wide screen scenario or not.

Even more examples!

If you want more of this, I’ve created an entire collection of similar responsive demos for you to enjoy!

Screenshot of collection page on CodePen, showing the six most recent demos added.
Collection of responsive demos.

The post DRY State Switching With CSS Variables: Fallbacks and Invalid Values appeared first on CSS-Tricks.

Categories: Designing, Others Tags: