Tag: Properties

SVG Properties and CSS

There are many Scalable Vector Graphics (SVG), but only certain attributes can be applied as CSS to SVG. Presentation attributes are used to style SVG elements and can be used as CSS properties. Some of these attributes are SVG-only while others are already shared in CSS, such as font-size or opacity.

For example, to change the color of a <circle> element to red, use the fill property in CSS. The fill attribute is a presentation attribute, therefore it can be used as a CSS property:

circle {   fill: red; }

See the Pen
vMqaay
by Geoff Graham (@geoffgraham)
on CodePen.

So, with that, let’s take a deep and thorough dive into all of the SVG elements that are available to us as well as the CSS properties for them. We’ll also look at various styling approaches, including general presentational styles and animations.

SVG Elements by Category

The presentation attributes that can be used as CSS properties can be found below. For reference, supported elements will be classified by category. This does not include deprecated elements.

Element Type Elements
Container elements <a>
<defs>
<g>
<marker>
<mask>
<pattern>
<svg>
<switch>
<symbol>
Filter primitive elements <feBlend>
<feColorMatrix>
<feComponentTransfer>
<feComposite>
<feConvolveMatrix>
<feDiffuseLighting>
<feDisplacementMap>
<feFlood>
<feGaussianBlur>
<feImage>
<feMerge>
<feMorphology>
<feOffset>
<feSpecularLighting>
<feTile>
<feTurbulence>
Gradient elements <linearGradient>
<radialGradient>
<stop>
Graphics elements <circle>
<ellipse>
<image>
<line>
<path>
<polygon>
<polyline>
<rect>
<text>
<use>
Shape elements <circle>
<ellipse>
<line>
<path>
<polygon>
<polyline>
<rect>
Text content elements <text>
<textPath>
<tspan>
Properties shared between CSS and SVG

Font properties

Presentation attribute Supported elements
font Text content elements
font-family Text content elements
font-size Text content elements
font-size-adjust Text content elements
font-stretch Text content elements
font-style Text content elements
font-variant Text content elements
font-weight Text content elements

Text properties

Presentation attribute Supported elements
direction <text>
<tspan>
letter-spacing Text content elements
text-decoration Text content elements
unicode-bidi Text content elements
word-spacing Text content elements
writing-mode <text>

Masking properties

Presentation attribute Supported elements
overflow <foreignObject>
<image>
<marker>
<pattern>
<svg>
<symbol>

Interactivity properties

Presentation attribute Supported elements
cursor Container elements
Graphics elements

Color properties

Presentation attribute Supported elements
color Applies to elements using:
fill
stroke
stop-color
flood-color
lighting-color

Visibility properties

Presentation attribute Supported elements
display Graphics elements
Text content elements
<a>
<foreignObject>
<g>
<svg>
<switch>
visibility Graphics elements
Text content elements
SVG CSS Properties

Text properties

Presentation attribute Supported elements
alignment-baseline <textPath>
<tspan>
baseline-shift <textPath>
<tspan>
dominant-baseline Text content elements
glyph-orientation-horizontal Text content elements
glyph-orientation-vertical Text content elements
kerning Text content elements
text-anchor Text content elements

Clip properties

Presentation attribute Supported elements
clip <foreignObject>
<image>
<marker>
<pattern>
<svg>
<symbol>
clip-path Container elements
Graphics elements
clip-rule <clipPath>

Masking properties

Presentation attribute Supported elements
mask Container elements
Graphics elements
opacity Graphics elements
<a>
<defs>
<g>
<marker>
<pattern>
<svg>
<switch>
<symbol>

Filter effects

Presentation attribute Supported elements
enable-background Container elements
filter Container elements
Graphics elements
flood-color <feFlood>
flood-opacity <feFlood>
lighting-color <feDiffuseLighting>
<feSpecularLighting>

Gradient properties

Presentation attribute Supported elements
stop-color <stop>
stop-opacity <stop>

Interactivity properties

Presentation attribute Supported elements
pointer-events Graphics elements

Color properties

Presentation attribute Supported elements
color-profile <image> referring to raster image

Painting properties

Presentation attribute Supported elements
color-interpolation Container elements
Graphics elements
color-interpolation-filters Filter primitive elements
color-rendering Container elements
Graphics elements
fill Shape elements
Text content elements
fill-rule Shape elements
Text content elements
fill-opacity Shape elements
Text content elements
image-rendering <image>
marker <line>
<path>
<polygon>
<polyline>
marker-start <line>
<path>
<polygon>
<polyline>
marker-mid <line>
<path>
<polygon>
<polyline>
marker-end <line>
<path>
<polygon>
<polyline>
shape-rendering Shape elements
stroke Shape elements
Text content elements
stroke-dasharray Shape elements
Text content elements
stroke-dashoffset Shape elements
Text content elements
stroke-linecap Shape elements
Text content elements
stroke-linejoin Shape elements
Text content elements
stroke-miterlimit Shape elements
Text content elements
stroke-opacity Shape elements
Text content elements
stroke-width Shape elements
Text content elements
text-rendering <text>
SVG 2

While presentation attributes can be used as CSS properties to style SVG, what about controlling the coordinates and dimensions of SVG elements using CSS? SVG 2, which is in Candidate Recommendation at the time of this writing, makes it is possible to style and animate these properties.

The SVG 2 specification states:

Some styling properties can be specified not only in style sheets and ‘style‘ attributes, but also in presentation attributes. These are attributes whose name matches (or is similar to) a given CSS property and whose value is parsed as a value of that property.”

Not only does it mean that SVG properties can be styled using CSS as presentation attributes or in style sheets, but this also can be applied to CSS pseudo-classes such as :hover or :active.

SVG 2 also introduces more presentation attributes that can be used as styling properties. These attributes can be found in SVG 2 specification.

Element-specific properties

It is important to note that not every SVG element will support the same CSS properties. Much like how there are CSS properties that can be applied to certain SVG elements, there are specific properties that are supported by certain SVG elements.

For example, the <circle>or <ellipse> elements support the cxand cyproperties as coordinates of the center of the shape. The <ellipse> element also supports the rx and ry properties as the radius, but the <circle> element cannot use these properties.

Geometry properties

In SVG 2, properties such as rx and ry are defined as geometry properties. Geometry properties can be used as CSS properties, just like presentation attributes such as fill or stroke properties. These CSS properties and the corresponding SVG elements include:

SVG Element Geometry Property
<circle> cx
cy
r
<ellipse> cx
cy
rx
ry
<rect> rx
ry
height
width
x
y
<path> path
<image> height
width
x
y
<foreignObject> height
width
x
y
<svg> code>height
width
x
y
Positioning SVG elements

SVG 2 also makes it is possible to position SVG elements using CSS. Let’s begin with drawing a rectangle shape having the following SVG:

<svg width="170" height="170">   <rect x="10" y="10" width="150" height="150" /> </svg>

And the following CSS:

rect {   fill: #6e40aa; }

See the Pen
QPeNGj
by Geoff Graham (@geoffgraham)
on CodePen.

This will produce a rectangle shape with its coordinates set to 10, 10. With SVG 2, x and y can be applied as CSS properties:

/* This will work with SVG 2 */ rect {   x: 10;   y: 10;   ... }

The SVG code would be reduced to this:

<svg width="170" height="170">   <rect width="150" height="150" /> </svg>

You can even set the width and height for the <rect> element using CSS like so:

rect {   ...   width: 150px;   height: 150px;   ... }

That leaves us with just the following for SVG markup:

<svg width="170" height="170">   <rect /> </svg>

See the Pen
Positioning SVG elements
by Katherine Kato (@kathykato)
on CodePen.

At the time of writing, the following demos will work in Blink (e.g. Chrome and Opera) and WebKit (e.g. Safari) browsers as these browsers support SVG 2 features. Until then, let’s dive into how to override SVG properties using CSS.

SVG shape morphing

The <path> element can be overridden with CSS to create shape morphing.

The SVG paths that morph one into the other must have the same number of points or else the morphing will not work.

Let’s start with drawing a <path> element in the shape of a triangle. Using the d property will specify the shape of the <path> element:

<svg height="220" width="300">   <path d="M150 10 L40 200 L260 200Z" /> </svg>

To get the triangle to morph into a different shape, let’s override the SVG <path> element with the d property with CSS:

path {   d: path("M150, 10 L40, 200 L260, 200Z");   fill: #4c6edb; }

Let’s also add a :active pseudo-class to the <path> property so when the element is clicked, the shape will morph into a square and change its fill color. Let’s also add a transition property to make the shape morphing action appear smooth. Here is the CSS:

path:active {   d: path("M150, 10 L40, 200 L260, 200 L260, 200Z");   fill: #4c6edb;   transition: all 0.35s ease; }

And the SVG would be:

<svg height="220" width="300">   <path /> </svg>

See the Pen
SVG shape morphing
by Katherine Kato (@kathykato)
on CodePen.

Want another demo? Here is a cool demo from Chris Coyier demonstrating SVG shape morphing on hover!

See the Pen
Simple Path Examples
by Chris Coyier (@chriscoyier)
on CodePen.

Animating SVG properties

SVG properties can be animated using CSS through CSS animations and transitions.

In this demo, we will draw various SVG <circle> elements and create a wave animation. Start by drawing five <circle> elements:

<svg width="350" height="250">   <circle class="shape" />   <circle class="shape" />   <circle class="shape" />   <circle class="shape" />   <circle class="shape" /> </svg>

We’ll be using CSS variables and :nth-child() CSS pseudo-class to define each .shape class. The .shape class will have a cy of 50 and a r of 20. Each of the .shape classes will have their own cx and fill CSS properties set:

:root {   --color-1: #6e40aa;   --color-2: #4c6edb;   --color-3: #24aad8;   --color-4: #1ac7c2;   --color-5: #1ddea3; }  .shape {   cy: 50;   r: 20; }  .shape:nth-child(1) {   cx: 60;   fill: var(--color-1); }  .shape:nth-child(2) {   cx: 120;   fill: var(--color-2); }  .shape:nth-child(3) {   cx: 180;   fill: var(--color-3); }  .shape:nth-child(4) {   cx: 240;   fill: var(--color-4); }  .shape:nth-child(5) {   cx: 300;   fill: var(--color-5); }

Here is how it should look so far.

See the Pen
Animating SVG properties: Pre-animation
by Geoff Graham (@geoffgraham)
on CodePen.

Now it’s time to animate! Start by using @keyframes rule to define the moveCircle animation:

@keyframes moveCircle {   50% {     cy: 150;     r: 13;   } }

This will get each <circle> element to change their cy coordinates from 50 to 150 and r from 20 to 13. Add the following to the CSS to the .shape class get the animation running infinitely:

.shape {   ...   animation: moveCircle 1250ms ease-in-out both infinite; }

Finally, add an animation-delay to each of the .shape classes to the CSS with the exception of .shape:nth-child(1) like this:

.shape:nth-child(2) {   ...   animation-delay: 100ms; }  .shape:nth-child(3) {   ...   animation-delay: 200ms; }  .shape:nth-child(4) {   ...   animation-delay: 300ms; }  .shape:nth-child(5) {   ...   animation-delay: 400ms; }

See the Pen
Animating SVG properties
by Katherine Kato (@kathykato)
on CodePen.

Shapes in SVG <pattern> elements can also be animated using CSS. Here is a cool demo by Dudley Storey showcasing that!

See the Pen
Screen
by Dudley Storey (@dudleystorey)
on CodePen.

Wrapping up

As SVG 1.1 is the current standard, few browsers currently support SVG 2 features. It is not recommended to put these techniques into production yet. SVG 2 implementation is currently at Candidate Recommendation stage, thus support for styling SVG geometry properties with CSS should improve in the future.

The post SVG Properties and CSS appeared first on CSS-Tricks.

CSS-Tricks

Breaking CSS Custom Properties out of :root Might Be a Good Idea

CSS Custom Properties have been a hot topic for a while now, with tons of great articles about them, from great primers on how they work to creative tutorials to do some real magic with them. If you’ve read more than one or two articles on the topic, then I’m sure you’ve noticed that they start by setting up the custom properties on the :root about 99% of the time.

While putting custom properties on the :root is great for things that you need to be available throughout your site, there are times when it makes more sense to scope your custom properties locally.

In this article, we’ll be exploring:

  • Why we put custom properties on the :root to begin with.
  • Why global scoping isn’t right for everything.
  • How to overcome class clashing with locally scoped custom properties

What’s the deal with custom properties and :root?

Before we jump into looking at the global scope, I think it’s worth looking at why everyone sets custom properties in the :root to begin with.

I’ve been declaring custom properties on the :root without even a second thought. Pretty much everyone does it without even a mention of why — including the official specification.

When the subject of :root is actually breached, it mentions how :root is the same as html, but with higher specificity, and that’s about it.

But does that higher specificity really matter?

Not really. All it does is select html with a higher specificity, the same way a class selector has higher specificity than an element selector when selecting a div.

:root {   --color: red; }  html {   --color: blue; }  .example {   background: var(--color);   /* Will be red because of :root's higher specificity */ }

The main reason that :root is suggested is because CSS isn’t only used to style HTML documents. It is also used for XML and SVG files.

In the case of XML and SVG files, :root isn’t selecting the html element, but rather their root (such as the svg tag in an SVG file).

Because of this, the best practice for a globally-scoped custom property is the :root. But if you’re making a website, you can throw it on an html selector and not notice a difference.

That said, with everyone using :root, it has quickly become a “standard.” It also helps separate variables to be used later on from selectors which are actively styling the document.

Why global scope isn’t right for everything

With CSS pre-processors, like Sass and Less, most of us keep variables tucked away in a partial dedicated to them. That works great, so why should we consider locally scoping variables all of a sudden?

One reason is that some people might find themselves doing something like this.

:root {   --clr-light: #ededed;   --clr-dark: #333;   --clr-accent: #EFF;   --ff-heading: 'Roboto', sans-serif;   --ff-body: 'Merriweather', serif;   --fw-heading: 700;   --fw-body: 300;   --fs-h1: 5rem;   --fs-h2: 3.25rem;   --fs-h3: 2.75rem;   --fs-h4: 1.75rem;   --fs-body: 1.125rem;   --line-height: 1.55;   --font-color: var(--clr-light);   --navbar-bg-color: var(--clr-dark);   --navbar-logo-color: var(--clr-accent);   --navbar-border: thin var(--clr-accent) solid;   --navbar-font-size: .8rem;   --header-color: var(--clr-accent);   --header-shadow: 2px 3px 4px rgba(200,200,0,.25);   --pullquote-border: 5px solid var(--clr-light);   --link-fg: var(--clr-dark);   --link-bg: var(--clr-light);   --link-fg-hover: var(--clr-dark);   --link-bg-hover: var(--clr-accent);   --transition: 250ms ease-out;   --shadow: 2px 5px 20px rgba(0, 0, 0, .2);   --gradient: linear-gradient(60deg, red, green, blue, yellow);   --button-small: .75rem;   --button-default: 1rem;   --button-large: 1.5rem; }

Sure, this gives us one place where we can manage styling with custom properties. But, why do we need to define my --header-color or --header-shadow in my :root? These aren’t global properties, I’m clearly using them in my header and no where else.

If it’s not a global property, why define it globally? That’s where local scoping comes into play.

Locally scoped properties in action

Let’s say we have a list to style, but our site is using an icon system — let’s say Font Awesome for simplicity’s sake. We don’t want to use the disc for our ul bullets — we want a custom icon!

If I want to switch out the bullets of an unordered list for Font Awesome icons, we can do something like this:

ul {   list-style: none; }  li::before {   content: "\f14a"; /* checkbox */   font-family: "Font Awesome Free 5";   font-weight: 900;   float: left;   margin-left: -1.5em; }

While that’s super easy to do, one of the problems is that the icon becomes abstract. Unless we use Font Awesome a lot, we aren’t going to know that f14a means, let alone be able to identify it as a checkbox icon. It’s semantically meaningless.

We can help clarify things with a custom property here.

ul {   --checkbox-icon: "\f14a";   list-style: none; }

This becomes a lot more practical once we start having a few different icons in play. Let’s up the complexity and say we have three different lists:

<ul class="icon-list checkbox-list"> ... </ul>  <ul class="icon-list star-list"> ... </ul>  <ul class="icon-list bolt-list"> ... </ul>

Then, in our CSS, we can create the custom properties for our different icons:

.icon-list {   --checkbox: "\f14a";   --star: "\f005";   --bolt: "\f0e7";    list-style: none; }

The real power of having locally scoped custom properties comes when we want to actually apply the icons.

We can set content: var(--icon) on our list items:

.icon-list li::before {   content: var(--icon);   font-family: "Font Awesome Free 5";   font-weight: 900;   float: left;   margin-left: -1.5em; }

Then we can define that icon for each one of our lists with more meaningful naming:

.checkbox-list {   --icon: var(--checkbox); }  .star-list {   --icon: var(--star); }  .bolt-list {   --icon: var(--bolt); }

We can step this up a notch by adding colors to the mix:

.icon-list li::before {   content: var(--icon);   color: var(--icon-color);   /* Other styles */ }

Moving icons to the global scope

If we’re working with an icon system, like Font Awesome, then I’m going to assume that we’d be using them for more than just replacing the bullets in unordered lists. As long as we’re using them in more than one place it makes sense to move the icons to the :root as we want them to be available globally.

Having icons in the :root doesn’t mean we can’t still take advantage of locally scoped custom properties, though!

:root {   --checkbox: "\f14a";   --star: "\f005";   --bolt: "\f0e7";      --clr-success: rgb(64, 209, 91);   --clr-error: rgb(219, 138, 52);   --clr-warning: rgb(206, 41, 26); }  .icon-list li::before {   content: var(--icon);   color: var(--icon-color);   /* Other styles */ }  .checkbox-list {   --icon: var(--checkbox);   --icon-color: var(--clr-success); }  .star-list {   --icon: var(--star);   --icon-color: var(--clr-warning); }  .bolt-list {   --icon: var(--bolt);   --icon-color: var(--clr-error); }

Adding fallbacks

We could either put in a default icon by setting it as the fallback (e.g. var(--icon, "/f1cb")), or, since we’re using the content property, we could even put in an error message var(--icon, "no icon set").

See the Pen
Custom list icons with CSS Custom Properties
by Kevin (@kevinpowell)
on CodePen.

By locally scoping the --icon and the --icon-color variables, we’ve greatly increased the readability of our code. If someone new were to come into the project, it will be a whole lot easier for them to know how it works.

This isn’t limited to Font Awesome, of course. Locally scoping custom properties also works great for an SVG icon system:

:root {   --checkbox: url(../assets/img/checkbox.svg);   --star: url(../assets/img/star.svg);   --baby: url(../assets/img/baby.svg); }  .icon-list {   list-style-image: var(--icon); }  .checkbox-list { --icon: checkbox; } .star-list { --icon: star; } .baby-list { --icon: baby; }

Using locally scoped properties for more modular code

While the example we just looked at works well to increase the readability of our code — which is awesome — we can do a lot more with locally scoped properties.

Some people love CSS as it is; others hate working with the global scope of the cascade. I’m not here to discuss CSS-in-JS (there are enough really smart people already talking about that), but locally scoped custom properties offer us a fantastic middle ground.

By taking advantage of locally scoped custom properties, we can create very modular code that takes a lot of the pain out of trying to come up with meaningful class names.

Let’s um, scope the scenario.

Part of the reason people get frustrated with CSS is that the following markup can cause problems when we want to style something.

<div class="card">   <h2 class="title">This is a card</h2>   <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Libero, totam.</p>   <button class="button">More info</button> </div>  <div class="cta">   <h2 class="title">This is a call to action</h2>   <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Aliquid eveniet fugiat ratione repellendus ex optio, ipsum modi praesentium, saepe, quibusdam rem quaerat! Accusamus, saepe beatae!</p>   <button class="button">Buy now</button> </div>

If I create a style for the .title class, it will style both the elements containing the .card and .cta classes at the same time. We can use a compound selector (i.e. .card .title), but that raises the specificity which can lead to less maintainability. Or, we can take a BEM approach and rename our .title class to .card__title and .cta__title to isolate those elements a little more.

Locally scoped custom properties offer us a great solution though. We can apply them to the elements where they’ll be used:

.title {   color: var(--title-clr);   font-size: var(--title-fs); }  .button {   background: var(--button-bg);   border: var(--button-border);   color: var(--button-text); }

Then, we can control everything we need within their parent selectors, respectively:

.card {   --title-clr: #345;   --title-fs: 1.25rem;   --button-border: 0;   --button-bg: #333;   --button-text: white; }  .cta {   --title-clr: #f30;   --title-fs: 2.5rem;   --button-border: 0;   --button-bg: #333;   --button-text: white; }

Chances are, there are some defaults, or commonalities, between buttons or titles even when they are in different components. For that, we could build in fallbacks, or simply style those as we usually would.

.button {   /* Custom variables with default values */   border: var(--button-border, 0);    /* Default: 0 */   background: var(--button-bg, #333); /* Default: #333 */   color: var(--button-text, white);   /* Default: white */    /* Common styles every button will have */   padding: .5em 1.25em;   text-transform: uppercase;   letter-spacing: 1px; }

We could even use calc() to add a scale to our button, which would have the potential to remove the need for .btn-sm, btn-lg type classes (or it could be built into those classes, depending on the situation).

.button {   font-size: calc(var(--button-scale) * 1rem);   /* Multiply `--button-scale` by `1rem` to add unit */ }  .cta {   --button-scale: 1.5; }

Here is a more in-depth look at all of this in action:

See the Pen
Custom list icons with CSS Custom Properties
by Kevin (@kevinpowell)
on CodePen.

Notice in that example above that I have used some generic classes, such as .title and .button, which are styled with locally scoped properties (with the help of fallbacks). With those being setup with custom properties, I can define those locally within the parent selector, effectively giving each its own style without the need of an additional selector.

I also set up some pricing cards with modifier classes on them. Using the generic .pricing class, I set everything up, and then using modifier classes, I redefined some of the properties, such as --text, and --background, without having to worry about using compound selectors or additional classes.

By working this way, it makes for very maintainable code. It’s easy to go in and change the color of a property if we need to, or even come in and create a completely new theme or style, like the rainbow variation of the pricing card in the example.

It takes a bit of foresight when initially setting everything up, but the payoff can be awesome. It might even seem counter-intuitive to how you are used to approaching styles, but next time you go to create a custom property, try keeping it defined locally if it doesn’t need to live globally, and you’ll start to see how useful it can be.

The post Breaking CSS Custom Properties out of :root Might Be a Good Idea appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Do CSS Custom Properties Beat Sass Loops?

I reckon that a lot of our uses of Sass maps can be replaced with CSS Custom properties – but hear me out for a sec.

When designing components we often need to use the same structure of a component but change its background or text color based on a theme. For example, in an alert, we might need a warning style, an error style, and a success style – each of which might be slightly different, like this:

There’s a few ways we could tackle building this with CSS, and if you were asking me a couple of years ago, I would’ve tried to solve this problem with Sass maps. First, I would have started with the base alert styles but then I’d make a map that would hold all the data:

$ alertStyles: (   error: (     theme: #fff5f5,     icon: 'error.svg',     darkTheme: #f78b8b   ),   success: (     theme: #f0f9ef,     icon: 'success.svg',     darkTheme: #7ebb7a   ),   warning: (     theme: #fff9f0,     icon: 'warning.svg',     darkTheme: #ffc848   ) );

Then we can loop through that data to change our core alert styles, like this:

@each $ state, $ property in $ alertStyles {   $ theme: map-get($ property, theme);   $ darkTheme: map-get($ property, darkTheme);   $ icon: map-get($ property, icon);      .alert-#{$ state} {     background-color: $ theme;     border-color: $ darkTheme;       &:before {       background-color: $ darkTheme;       background-image: url($ icon);     }     .alert-title {       color: $ darkTheme;     }   } }

Pretty complicated, huh? This would output classes such as .alert-error, .alert-success and .alert-warning, each of which would have a bunch of CSS within them that overrides the default alert styles.

This would leave us with something that looks like this demo:

See the Pen
Alerts – Sass Loops
by Robin Rendle (@robinrendle)
on CodePen.

However! I’ve always found that using Sass maps and looping over all this data can become unwieldy and extraordinarily difficult to read. In recent projects, I’ve stumbled into fantastically complicated uses of maps and slowly closed the file as if I’d stumbled into a crime scene.

How do we keep the code easy and legible? Well, I think that CSS Custom Properties makes these kinds of loops much easier to read and therefore easier to edit and refactor in the future.

Let’s take the example above and refactor it so that it uses CSS Custom Properties instead. First we’ll set out core styles for the .alert component like so:

See the Pen
Alerts – Custom Variables 1
by Robin Rendle (@robinrendle)
on CodePen.

As we create those base styles, we can setup variables in our .alert class like this:

.alert {   --theme: #ccc;   --darkTheme: #777;   --icon: '';   background: var(--theme);   border: 1px solid var(--darkTheme);   /* other styles go here */      &:before {     background-image: var(--icon);   } }

We can do a lot more with CSS Custom Properties than changing an interface to a dark mode or theme. I didn’t know until I tried that it’s possible to set an image in a custom property like that – I simply assumed it was for hex values.

Anyway! From there, we can style each custom .alert class like .alert-warning by overriding these properties in .alert:

.alert-success {   --theme: #f0f9ef;   --darkTheme: #7ebb7a;   --icon: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/14179/success.svg); }  .alert-error {   --theme: #fff5f5;   --darkTheme: #f78b8b;   --icon: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/14179/error.svg); }  .alert-warning {   --theme: #fff9f0;    --darkTheme: #ffc848;   --icon: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/14179/warning.svg); } 

And that’s about it! We’ll get the exact same visual interface that we had with a Sass loop:

See the Pen
Alerts – Custom Variables 2
by Robin Rendle (@robinrendle)
on CodePen.

However! I think there’s an enormous improvement here that’s been made in terms of legibility. It’s much easier to look at this code and to understand it right off the bat. With the Sass loop it almost seems like we are trying to do a lot of clever things in one place – namely, nest classes within other classes and create the class names themselves. Not to mention we then have to go back and forth between the original Sass map and our styles.

With CSS Custom Properties, all the styles are contained within the original .alert.

There you have it! I think there’s not much to mention here besides the fact that CSS Custom Properties can make code more legible and maintainable in the future. And I reckon that’s something we should all be a little excited about.

Although there is one last thing: we should probably be aware of browser support whilst working with Custom Properties although it’s pretty good across the board.

The post Do CSS Custom Properties Beat Sass Loops? appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Did you know that CSS Custom Properties can handle images too?

So you might be aware of CSS Custom Properties that let you set a variable, such as a theme color, and then apply it to multiple classes like this:

:root {   --theme: #777; }  .alert {   background: var(—-theme); }  .button {   background: var(—-theme); }

Well, I had seen this pattern so often that I thought Custom Properties could only be used for color values like rgba or hex – although that’s certainly not the case! After a little bit of experimentation and sleuthing around, I realized that it’s possible to use Custom Properties to set image paths, too.

Here’s an example of that in action:

:root {   --errorIcon: url(error.svg) }  .alert {   background-image: var(--errorIcon); }  .form-error {   background-image: var(--errorIcon); }

Kinda neat, huh? I think this could be used to make an icon system where you could define a whole list of images in the :root and call it whenever you needed to. Or you could make it easier to theme certain classes based on their state or perhaps in a media query, as well. Remember, too, that custom properties can be overridden within an element:

:root {   --alertIcon: url(alert-icon.svg) }  .alert {   background-image: var(--alertIcon); }  .form-error {   --alertIcon: url(alert-icon-error.svg)   background-image: var(--alertIcon); }

And, considering that custom properties are selectable in JavaScript, think about the possibilities of swapping out images as well. I reckon this might useful to know!

The post Did you know that CSS Custom Properties can handle images too? appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Responsive Designs and CSS Custom Properties: Building a Flexible Grid System

Last time, we looked at a few possible approaches for declaring and using CSS custom properties in responsive designs. In this article, we’ll take a closer look at CSS variables and how to use them in reusable components and modules. We will learn how to make our variables optional and set fallback values.

As an example, we will build a simple grid system based on flexbox. Grid systems play a vital role in responsive designs. However, building a grid system that is flexible and lightweight at the same time can be a tricky task. Let’s see what the common approaches towards grid systems are and how CSS custom properties can help us build them.

Article Series:

  1. Defining Variables and Breakpoints
  2. Building a Flexible Grid System (This Post)

A simple CSS grid system

Let’s start with a 12-column grid system:

.container { 	max-width: 960px; 	margin: 0 auto; 	display: flex; }  .col-1 { flex-basis: 8.333%; } .col-2 { flex-basis: 16.666%; } .col-3 { flex-basis: 25%; } .col-4 { flex-basis: 33.333%; } .col-5 { flex-basis: 41.666%; } .col-6 { flex-basis: 50%; } /* and so on up to 12... */

See the Pen
#5 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

There’s quite a lot of repetition and hard-coded values here. Not to mention how many more will be generated once we add more breakpoints, offset classes, etc.

Building a grid system with Sass

To make our grid example more readable and maintainable, let’s use Sass to preprocess our CSS:

$ columns: 12; // Number of columns in the grid system  .container { 	display: flex; 	flex-wrap: wrap; 	margin: 0 auto; 	max-width: 960px; }  @for $ width from 1 through $ columns { 	.col-#{$ width} { 		flex-basis: $ width / $ columns * 100%; 	}   }

See the Pen
#6 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

This is definitely much easier to work with. As we develop our grid further and, let’s say, would like to change it from 12 columns to 16 columns, all we have to do is to update a single variable (in comparison to dozens of classes and values). But… as long as our Sass is shorter and more maintainable now, the compiled code is identical to the first example. We are still going to end up with a massive amount of code in the final CSS file. Let’s explore what happens if we try to replace the Sass variables with CSS custom properties instead.

Building a grid system with CSS custom properties

Before we start playing with CSS custom properties, let’s start with some HTML first. Here’s the layout we’re aiming for:

It consists of three elements: a header, a content section and a sidebar. Let’s create markup for this view, giving each of the elements a unique semantic class (header, content, sidebar) and a column class which indicates that this element is a part of a grid system:

<div class="container"> 	<header class="header column"> 		header 	</header> 	<main class="content column"> 		content 	</main> 	<aside class="sidebar column"> 		sidebar 	</aside> </div>

Our grid system, as before, is based on a 12-column layout. You can envision it as an overlay covering our content areas:

So .header takes all 12 columns, .content takes eight columns (66.(6)% of the total width) and .sidebar takes four columns (33.(3)% of the total width). In our CSS, we would like to be able to control the width of each section by changing a single custom property:

.header { 	--width: 12; }  .content { 	--width: 8; }  .sidebar { 	--width: 4; }

To make it work, all we need to do is write a rule for the .column class. Lucky for us, most of the work is already done! We can re-use the Sass from the previous chapter and replace the Sass variables with CSS custom properties:

.container { 	display: flex; 	flex-wrap: wrap; 	margin: 0 auto; 	max-width: 960px; }  .column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: 0; /* Default width of the element */  	flex-basis: calc(var(--width) / var(--columns) * 100%); }

Notice two important changes here:

  1. The --columns variable is now declared inside of the .column rule. The reason is that this variable is not supposed to be used outside of the scope of this class.
  2. The math equation we perform in the flex-basis property is now enclosed within a calc() function. Math calculations that are written in Sass are compiled by the preprocessor and don’t need additional syntax. calc(), on the other hand, lets us perform math calculations in live CSS. The equation always needs to be wrapped within a calc() function.

On a very basic level, that’s it! We’ve just built a 12-column grid system with CSS custom properties. Congratulations! We could call it a day and happily finish this article right now, but… we usually need a grid system that is a bit more sophisticated. And this is when things are getting really interesting.

See the Pen
#8 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Adding a breakpoint to the grid

Most times, we need layouts to look different on various screen sizes. Let’s say that in our case we want the layout to remain as it is on a large viewport (e.g. desktop) but have all three elements become full-width on smaller screens (e.g. mobile).

So, in this case, we would like our variables to look as follows:

.header { 	--width-mobile: 12; }  .content { 	--width-mobile: 12; 	--width-tablet: 8; /* Tablet and larger */ }  .sidebar { 	--width-mobile: 12; 	--width-tablet: 4; /* Tablet and larger */ }

.content and .sidebar each hold two variables now. The first variable (--width-mobile) is a number of columns an element should take by default, and the second one (--width-tablet) is the number of columns an element should take on larger screens. The .header element doesn’t change; it always takes the full width. On larger screens, the header should simply inherit the width it has on mobile.

Now, let’s update our .column class.

CSS variables and fallback

To make the mobile version work as expected, we need to alter the .column class as follows:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: var(--width-mobile, 0); /* Default width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }

Basically, we replace the value of the --width variable with --width-mobile. Notice that the var() function takes two arguments now. The first of them is a default value. It says: “If a --width-mobile variable exists in a given scope, assign its value to the --width variable.” The second argument is a fallback. In other words: “If a --width-mobile variable is not declared in a given scope, assign this fallback value to the --width variable.” We set this fallback to prepare for a scenario where some grid elements won’t have a specified width.

For example, our .header element has a declared --width-mobile variable which means the --width variable will be equal to it and the flex-basis property of this element will compute to 100%:

.header { 	--width-mobile: 12; }  .column { 	--columns: 12; 	--width: var(--width-mobile, 0); /* 12, takes the value of --width-mobile */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); /* 12 ÷ 12 × 100% = 100% */ }

If we remove the --width-mobile variable from the .header rule, then the --width variable will use a fallback value:

.header { 	/* Nothing here... */ }  .column { 	--columns: 12; 	--width: var(--width-mobile, 0); /* 0, takes the the fallback value */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); /* 0 ÷ 12 × 100% = 0% */ }

Now, as we understand how to set fallback for CSS custom properties, we can create a breakpoint, by adding a media query to our code:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: var(--width-mobile, 0); /* Default width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }  @media (min-width: 576px) { 	.column { 		--width: var(--width-tablet); /* Width of the element on tablet and up */ 	} }

This works exactly as expected, but only for the content and sidebar, i.e. for the elements that have specified both --width-mobile and --width-tablet. Why?

The media query we created applies to all .column elements, even those that don’t have a --width-tablet variable declared in their scope. What happens if we use a variable that is not declared? The reference to the undeclared variable in a var() function is then considered invalid at computed-value time, i.e. invalid at the time a user agent is trying to compute it in the context of a given declaration.

Ideally, in such a case, we would like the --width: var(--width-tablet); declaration to be ignored and the previous declaration of --width: var(--width-mobile, 0); to be used instead. But this is not how custom properties work! In fact, the invalid --width-tablet variable will still be used in the flex-basis declaration. A property that contains an invalid var() function always computes to its initial value. So, as flex-basis: calc(var(--width) / var(--columns) * 100%); contains an invalid var() function the whole property will compute to auto (the initial value for flex-basis).

What else we can do then? Set a fallback! As we learned before, a var() function containing a reference to the undeclared variable, computes to its fallback value, as long as it’s specified. So, in this case, we can just set a fallback to the --width-tablet variable:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: var(--width-mobile, 0); /* Default width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }  @media (min-width: 576px) { 	.column { 		--width: var(--width-tablet, var(--width-mobile, 0)); 	} }

See the Pen
#9 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

This will create a chain of fallback values, making the --width property use --width-tablet when available, then --width-mobile if --width-tablet is not declared, and eventually, 0 if neither of the variables is declared. This approach allows us to perform numerous combinations:

.section-1 { 	/* Flexible on all resolutions */ }  .section-2 { 	/* Full-width on mobile, half of the container's width on tablet and up */ 	--width-mobile: 12; 	--width-tablet: 6; } 	 .section-3 { 	/* Full-width on all resolutions */ 	--width-mobile: 12; } 	 .section-4 { 	/* Flexible on mobile, 25% of the container's width on tablet and up */ 	--width-tablet: 3; }

One more thing we can do here is convert the default 0 value to yet another variable so we avoid repetition. It makes the code a bit longer but easier to update:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width-default: 0; /* Default width, makes it flexible */ 	--width: var(--width-mobile, var(--width-default)); /* Width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }  @media (min-width: 576px) { 	.column { 		--width: var(--width-tablet, var(--width-mobile, var(--width-default))); 	} }

See the Pen
#10 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Now, we have a fully functional, flexible grid! How about adding some more breakpoints?

Adding more breakpoints

Our grid is already quite powerful but we often need more than one breakpoint. Fortunately, adding more breakpoints to our code couldn’t be easier. All we have to do is to re-use the code we already have and add one variable more:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width-default: 0; /* Default width, makes it flexible */ 	--width: var(--width-mobile, var(--width-default)); /* Width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }  @media (min-width: 576px) { 	.column { 		--width: var(--width-tablet, var(--width-mobile, var(--width-default))); 	} }  @media (min-width: 768px) { 	.column { 		--width: var(--width-desktop, var(--width-tablet, var(--width-mobile, var(--width-default)))); 	} }

See the Pen
#11 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Reducing fallback chains

One thing that doesn’t look that great in our code is that feedback chains are getting longer and longer with every breakpoint. If we’d like to tackle this issue, we can change our approach to something like this:

.column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: var(--width-mobile, 0); /* Width of the element */ 	 	flex-basis: calc(var(--width) / var(--columns) * 100%); }  @media (min-width: 576px) { 	.column { 		--width-tablet: var(--width-mobile); 		--width: var(--width-tablet); 	} }  @media (min-width: 768px) { 	.column { 		--width-desktop: var(--width-tablet); 		--width: var(--width-desktop); 	} }

See the Pen
#12 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

This code is doing exactly the same job but in a bit different way. Instead of creating a full fallback chain for each breakpoint, we set a value of each variable to the variable from the previous breakpoint as a default value.

Why so complicated?

It looks like we’ve done quite a lot of work to complete a relatively simple task. Why? The main answer is: to make the rest of our code simpler and more maintainable. In fact, we could build the same layout by using the techniques described in the previous part of this article:

.container { 	display: flex; 	flex-wrap: wrap; 	margin: 0 auto; 	max-width: 960px; }  .column { 	--columns: 12; /* Number of columns in the grid system */ 	--width: 0; /* Default width of the element */  	flex-basis: calc(var(--width) / var(--columns) * 100%); }  .header { 	--width: 12; }  .content { 	--width: 12; }  .sidebar { 	--width: 12; }  @media (min-width: 576px) { 	.content { 		--width: 6; 	} 	 	.sidebar { 		--width: 6; 	} }  @media (min-width: 768px) { 	.content { 		--width: 8; 	} 	 	.sidebar { 		--width: 4; 	} }

In a small project, this approach could work perfectly well. For the more complex solutions, I would suggest considering a more scalable solution though.

Why should I bother anyway?

If the presented code is doing a very similar job to what we can accomplish with preprocessors such as Sass, why should we bother at all? Are custom properties any better? The answer, as usually, is: it depends. An advantage of using Sass is better browser support. However, using custom properties has a few perks too:

  1. It’s plain CSS. In other words, it’s a more standardized, dependable solution, independent from any third parties. No compiling, no package versions, no weird issues. It just works (apart from the browsers where it just doesn’t work).
  2. It’s easier to debug. That’s a questionable one, as one may argue that Sass provides feedback through console messages and CSS does not. However, you can’t view and debug preprocessed code directly in a browser, whilst working with CSS variables, all the code is available (and live!) directly in DevTools.
  3. It’s more maintainable. Custom properties allow us to do things simply impossible with any preprocessor. It allows us to make our variables more contextual and, therefore, more maintainable. Plus, they are selectable by JavaScript, something Sass variables are not.
  4. It’s more flexible. Notice, that the grid system we’ve built is extremely flexible. Would you like to use a 12-column grid on one page and a 15-column grid on another? Be my guest—it’s a matter of a single variable. The same code can be used on both pages. A preprocessor would require generating code for two separate grid systems.
  5. It takes less space. As long as the weight of CSS files is usually not the main bottleneck of page load performance, it still goes without saying that we should aim to optimize CSS files when possible. To give a better image of how much can be saved, I made a little experiment. I took the grid system from Bootstrap and rebuilt it from scratch with custom properties. The results are as follows: the basic configuration of the Bootstrap grid generates over 54KB of CSS whilst a similar grid made with custom properties is a mere 3KB. That’s a 94% difference! What is more, adding more columns to the Bootstrap grid makes the file even bigger. With CSS variables, we can use as many columns as we want without affecting the file size at all.

The files can be compressed to minimize the difference a bit. The gzipped Bootstrap grid takes 6.4KB in comparison to 0.9KB for the custom properties grid. This is still an 86% difference!

Performance of CSS variables

Summing up, using CSS custom properties has a lot of advantages. But, if we are making the browser do all the calculations that had been done by preprocessors, are we negatively affecting the performance of our site? It’s true that using custom properties and calc() functions will use more computing power. However, in cases similar to the examples we discussed in this article, the difference will usually be unnoticeable. If you’d like to learn more about this topic, I would recommend reading this excellent article by Lisi Linhart.

Not only grid systems

After all, understanding the ins and outs of custom properties may not be as easy as it seems. It will definitely take time, but it’s worth it. CSS variables can be a huge help when working on reusable components, design systems, theming and customizable solutions. Knowing how to deal with fallback values and undeclared variables may turn out to be very handy then.

Thanks for reading and good luck on your own journey with CSS custom properties!

The post Responsive Designs and CSS Custom Properties: Building a Flexible Grid System appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

Responsive Designs and CSS Custom Properties: Defining Variables and Breakpoints

CSS custom properties (a.k.a. CSS variables) are becoming more and more popular. They finally reached decent browser support and are slowly making their way into various production environments. The popularity of custom properties shouldn’t come as a surprise, because they can be really helpful in numerous use cases, including managing color palettes, customizing components, and theming. But CSS variables can also be really helpful when it comes to responsive design.

Article Series:

  1. Defining Variables and Breakpoints (This Post)
  2. Building a Flexible Grid System (Coming Tomorrow!)

Let’s consider an <article> element with a heading and a paragraph inside:

<article class="post"> 	<h2 class="heading">Post's heading</h2> 	<p class="paragraph"> 		Lorem ipsum dolor sit amet, consectetur adipisicing elit. 		Laudantium numquam adipisci recusandae officiis dolore tenetur, 		nisi, beatae praesentium, soluta ullam suscipit quas? 	</p> </article>

It’s a common scenario in such a case to change some sizes and dimensions depending on the viewport’s width. One way to accomplish this is by using media queries:

.post { 	padding: 0.5rem 1rem; 	margin: 0.5rem auto 1rem; }  .heading { 	font-size: 2rem; }  @media (min-width: 576px) { 	.post { 		padding: 1rem 2rem; 		margin: 1rem auto 2rem; 	} 	 	.heading { 		font-size: 3rem; 	} }

See the Pen
#1 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Such an approach gives us an easy way to control CSS properties on different screen sizes. However, it may be hard to maintain as the complexity of a project grows. When using media queries, keeping code readable and DRY at the same time quite often turns out to be challenging.

The most common challenges when scaling this pattern include:

  • Repeated selectors: Apart from bloating code with multiple declarations, it also makes future refactoring more difficult, e.g. every time a class name changes it requires remembering to update it in multiple places.
  • Repeated properties: Notice that when overwriting CSS rules within media queries, it requires repeating the entire declaration (e.g. font-size: 3rem;) even though it’s just the value (3rem) that actually changes.
  • Repeated media queries: To keep responsive styles contextual, it’s a common practice to include the same media queries in multiple places, close to the styles they override. Unfortunately, it not only makes code heavier, but also might make breakpoints much harder to maintain. On the other hand, keeping all responsive styles in one place, away from their original declarations, may be very confusing: we end up with multiple references to the same elements sitting in completely different places.

We can argue that repeated declarations and queries shouldn’t be such a big deal with proper file compression enabled, at least as long as we’re referring to performance. We can also merge multiple queries and optimize your code with post-processing tools. But wouldn’t it be easier to avoid these issues altogether?

There’s a lot of ways to avoid the issues listed above. One of them, that we will explore in this article, is to use CSS custom properties.

Using CSS variables for property values

There are plenty of amazing articles on the web explaining the concept of CSS custom properties. If you haven’t got chance to get familiar with them yet, I would recommend starting with one of the beginner articles on this topic such as this awesome piece by Serg Hospodarets as we are not going to get into details of the basic usage in this article.

The most common way of utilizing CSS custom properties in responsive design is to use variables to store values that change inside of media queries. To accomplish this, declare a variable that holds a value that is supposed to change, and then reassign it inside of a media query:

:root {   --responsive-padding: 1rem; }  @media (min-width: 576px) {                                :root {     --responsive-padding: 2rem;   } }  .foo { 	padding: var(--responsive-padding); }

Assigning variables to the :root selector is not always a good idea. Same as in JavaScript, having many global variables is considered a bad practice. In real life, try to declare the custom properties in the scope they will actually be used.

This way, we are avoiding multiple rules of the .foo class. We are also separating the logic (changing values) from the actual designs (CSS declarations). Adapting this approach in our example from above gives us the following CSS:

.post { 	--post-vertical-padding: 0.5rem; 	--post-horizontal-padding: 1rem; 	--post-top-margin: 0.5rem; 	--post-bottom-margin: 1rem; 	--heading-font-size: 2rem; }  @media (min-width: 576px) { 	.post { 		--post-vertical-padding: 1rem; 		--post-horizontal-padding: 2rem; 		--post-top-margin: 1rem; 		--post-bottom-margin: 2rem; 		--heading-font-size: 3rem; 	} }  .post { 	padding: var(--post-vertical-padding) var(--post-horizontal-padding); 	margin: var(--post-top-margin) auto  var(--post-bottom-margin); }  .heading { 	font-size: var(--heading-font-size); }

See the Pen
#2 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Notice that the use of variables in shorthand properties (e.g. padding, margin or font) allow some very interesting repercussions. As custom properties may hold almost any value (more on this later), even an empty string, it’s unclear how the value of a shorthand property will be separated out into longhand properties that are used in the cascade later. For example, the auto used in the margin property above may turn out to be a top-and-bottom margin, a left-and-right margin, a top margin, a right margin, a bottom margin or a left margin — it all depends on the values of the custom properties around.

It’s questionable whether the code looks cleaner than the one from the previous example, but on a larger scale, it’s definitely more maintainable. Let’s try to simplify this code a bit now.

Notice that some values are repeated here. What if we try to merge duplicate variables together? Let’s consider the following alteration:

:root { 	--small-spacing: 0.5rem; 	--large-spacing: 1rem; 	--large-font-size: 2rem; }  @media (min-width: 576px) { 	:root { 		--small-spacing: 1rem; 		--large-spacing: 2rem; 		--large-font-size: 3rem; 	} }  .post { 	padding: var(--small-spacing) var(--large-spacing); 	margin: var(--small-spacing) auto  var(--large-spacing); }  .heading { 	font-size: var(--large-font-size); }

See the Pen
#3 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

It looks cleaner but is it actually better? Not necessarily. For the sake of flexibility and readability, this may not be the right solution in every case. We definitely shouldn’t merge some variables just because they accidentally turned out to hold the same values. Sometimes, as long as we’re doing this as a part of a well thought out system, it may help us simplify things and preserve consistency across the project. However, in other cases, such a manner may quickly prove to be confusing and problematic. Now, let’s take a look at yet another way we can approach this code.

Using CSS variables as multipliers

CSS custom properties are a fairly new feature to the modern web. One of the other awesome features that rolled out in the last years is the calc() function. It lets us perform real math operations in live CSS. In terms of the browser support, it’s supported in all browsers that support CSS custom properties.

calc() tends to play very nicely with CSS variables, making them even more powerful. This means we can both use calc() inside custom properties and custom properties inside calc()!

For example, the following CSS is perfectly valid:

:root { 	--size: 2; } 	 .foo { 	--padding: calc(var(--size) * 1rem); /* 2 × 1rem = 2rem */ 	padding: calc(var(--padding) * 2);   /* 2rem × 2 = 4rem */ }

Why does this matter to us and our responsive designs? It means that we can use a calc() function to alter CSS custom properties inside media queries. Let’s say we have a padding that should have a value of 5px on mobile and 10px on desktop. Instead of declaring this property two times, we can assign a variable to it and multiply it by two on larger screens:

:root { 	--padding: 1rem; 	--foo-padding: var(--padding); }  @media (min-width: 576px) {                              	:root { 		--foo-padding: calc(var(--padding) * 2); 	} }  .foo { 	padding: var(--foo-padding); }

Looks fine, however all the values (--padding, calc(--padding * 2)) are away from their declaration (padding). The syntax may also be pretty confusing with two different padding variables (--padding and --foo-padding) and an unclear relationship between them.

To make things a bit clearer, let’s try to code it the other way around:

:root { 	--multiplier: 1; }  @media (min-width: 576px) {                              	:root { 		--multiplier: 2; 	} }  .foo { 	padding: calc(1rem * var(--multiplier)); }

This way, we accomplished the same computed output with much cleaner code! So, instead of using a variable for an initial value of the property (1rem), a variable was used to store a multiplier (1 on small screens and 2 on larger screens). It also allows us to use the --multiplier variable in other declarations. Let’s apply this technique to paddings and margins in our previous snippet:

:root { 	--multiplier: 1; }  @media (min-width: 576px) { 	:root { 		--multiplier: 2; 	} }  .post { 	padding: calc(.5rem * var(--multiplier)) 						calc(1rem  * var(--multiplier)); 	margin:  calc(.5rem * var(--multiplier)) 						auto 						calc(1rem  * var(--multiplier)); }

Now, let’s try to implement the same approach with typography. First, we’ll add another heading to our designs:

<h1 class="heading-large">My Blog</h1> <article class="post"> 	<h2 class="heading-medium">Post's heading</h2> 	<p class="paragraph"> 		Lorem ipsum dolor sit amet, consectetur adipisicing elit. 		Laudantium numquam adipisci recusandae officiis dolore tenetur, 		nisi, beatae praesentium, soluta ullam suscipit quas? 	</p> </article>

With multiple text styles in place, we can use a variable to control their sizes too:

:root { 	--headings-multiplier: 1; }  @media (min-width: 576px) { 	:root { 		--headings-multiplier: 3 / 2; 	} }  .heading-medium { 	font-size: calc(2rem * var(--headings-multiplier)) }  .heading-large { 	font-size: calc(3rem * var(--headings-multiplier)) }

You may have noticed that 3 / 2 is not a valid CSS value at all. Why does it not cause an error then? The reason is that the syntax for CSS variables is extremely forgiving, which means almost anything can be assigned to a variable, even if it’s not a valid CSS value for any existing CSS property. Declared CSS custom properties are left almost entirely un-evaluated until they are computed by a user agent in certain declarations. So, once a variable is used in a value of some property, this value will turn valid or invalid at the computed-value time.

Oh, and another note about that last note: in case you’re wondering, I used a value of 3 / 2 simply to make a point. In real life, it would make more sense to write 1.5 instead to make the code more readable.

Now, let’s take a look at the finished live example combining everything that we discussed above:

See the Pen
#4 Building responsive features with CSS custom properties
by Mikołaj (@mikolajdobrucki)
on CodePen.

Again, I would never advocate for combining calc() with custom properties to make the code more concise as a general rule. But I can definitely imagine scenarios in which it helps to keep code more organized and maintainable. This approach also allows the weight of CSS to be significantly reduced, when it’s used wisely.

In terms of readability, we can consider it more readable once the underlying rule is understood. It helps to explain the logic and relations between values. On the other hand, some may see it as less readable, because it’s tough to instantly read what a property holds as a value without first doing the math. Also, using too many variables and calc() functions at once may unnecessarily obscure code and make it harder to understand, especially for juniors and front-end developers who are not focused on CSS.

Conclusion

Summing up, there’s a lot of ways to use CSS custom properties in responsive design, definitely not limited to the examples shown above. CSS variables can be used simply to separate the values from the designs. They can also be taken a step further and be combined with some math. None of the presented approaches is better nor worse than the others. The sensibility of using them depends on the case and context.

Now that you know how CSS custom properties can be used in responsive design, I hope you will find a way to introduce them in your own workflow. Next up, we’re going to look at approaches for using them in reusable components and modules, so stay tuned for the next post tomorrow!

The post Responsive Designs and CSS Custom Properties: Defining Variables and Breakpoints appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art

Have you seen Diana Smith’s CSS drawings? Stunning. These far transcend the CSS drawings that sort of crudely replicate a flat SVG scene, like I might attempt. We were lucky enough for her to post some of her CSS drawing techniques here last year.

Well, Diana has also listed the top five CSS properties she uses to get these masterpieces done, and they are surprising in their plainness:

  1. border-radius
  2. box-shadow
  3. transform
  4. gradients
  5. overflow

…but of course, layered in trickery!

… for custom rounded elements that are meant to mimic organic objects like faces, it is imperative that you become intimately familiar with all eight available parameters in the border-radius property.

Diana shows her famous Francine drawing with each of the most used properties turned off:

Without border-radius
Without transform

Be sure to check out this VICE interview she did as well. She covers gems like the fact that Francine was inspired by American Dad (lol) and that the cross-browser fallbacks are both a fascinating and interesting mess.

Direct Link to ArticlePermalink

The post Diana Smith’s Top 5 CSS Properties She Uses to Produce CSS Art appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]