Tag: Properties

Global CSS options with custom properties

With a preprocessor, like Sass, building a logical “do this or don’t” setting is fairly straightforward:

$  option: false;  @mixin doThing {   @if $  option {     do-thing: yep;   } }  .el {   @include doThing; }

Can we do that in native CSS with custom properties? Mark Otto shows that we can. It’s just a smidge different.

html {   --component-shadow: 0 .5rem 1rem rgba(0,0,0,.1); }  .component {   box-shadow: var(--component-shadow); }  <!-- override the global anywhere more specific! like      <div class="component remove-shadow">      or      <body class="remove-shadow"> --> .remove-shadow {   --component-shadow: none; }

Direct Link to ArticlePermalink

The post Global CSS options with custom properties appeared first on CSS-Tricks.

CSS-Tricks

, , ,

Creating Color Themes With Custom Properties, HSL, and a Little calc()

Before the advent of CSS custom properties (we might call them “variables” in this article as that’s the spirit of them), implementing multiple color schemes on the same website usually meant writing separate stylesheets. Definitely not the most maintainable thing in the world. Nowadays, though, we can define variables in a single stylesheet and let CSS do the magic.

Even if you aren’t offering something like user-generated or user-chosen color themes, you might still use the concept of theming on your website. For example, it is fairly common to use different colors themes across different areas of the site.

We’re going to build out an example like this:

Same layout, different colors.

In this example, all that changes between sections is the color hue; the variations in lightness are always the same. Here’s an example of a simplified color palette for a specific hue:

A palette of multiple hues might look something like this:

This would take effort to do with RGB color value, but in HSL only one value changes.

Enter custom properties

Custom properties have been around for a while and are widely supported. Polyfills and other solutions for IE 11 are also available.

The syntax is very similar to traditional CSS. Here is an overview of the basic usage:

It’s common to see variables defined on the :root pseudo-element, which is always <html> in HTML, but with higher specificity. That said, variables can be defined on any element which is useful for scoping specific variables to specific elements. For example, here are variables defined on data attributes:

Adding calc() to the mix

Variables don’t have to be fixed values. We can leverage the power of the calc() function to automatically calculate values for us while adhering to a uniform pattern:

Since CSS doesn’t support loops, a preprocessor would be handy to generate a part of the code. But remember: CSS variables are not the same as Sass variables.

Implementing CSS variables

What we’re basically trying to do is change the color of the same component on different sections of the same page. Like this:

We have three sections in tabs with their own IDs: #food, #lifestyle, and #travel. Each section corresponds to a different hue. The  data-theme-attribute on the div.wrapper element defines which hue is currently in use.

When #travel is the active tab, we’re using the --first-hue variable, which has a value of 180°. That is what gets used as the --hue value on the section, resulting in a teal color:

<div class="wrapper" data-theme="travel">
.wrapper[data-theme="travel"] {   --hue: var(--first-hue);  /* = 180° = teal */ }

Clicking any of the tabs updates the data-theme attribute to the ID of the section, while removing the hash (#) from it. This takes a smidge of JavaScript. That’s one of the (many) nice things about CSS: they can be accessed and manipulated with JavaScript. This is a far cry from preprocessor variables, which compile into values at the build stage and are no longer accessible in the DOM.

<li><a href="#food">Food</a></li>
const wrapper = document.querySelector('.wrapper'); document.querySelector("nav").addEventListener('click', e => {   e.preventDefault();   e.stopPropagation();   // Get theme name from URL and ditch the hash   wrapper.dataset.theme = e.target.getAttribute('href').substr(1); })

Progressive enhancement

When we use JavaScript, we should be mindful of scenarios where a user may have disabled it. Otherwise, our scripts — and our UI by extension — are inaccessible. This snippet ensures that the site content is still accessible, even in those situations:

document.querySelectorAll('section').forEach((section, i) => {   if (i) { // hide all but the first section     section.style.display = 'none';   } })

This merely allows the tabs to scroll up the page to the corresponding section. Sure, theming is gone, but providing content is much more important.

While I chose to go with a single-page approach, it’s also possible to serve the sections as separate pages and set [data-theme] on the server side. 

Another approach

So far, we’ve assumed that color values change linearly and are thus subject to a mathematical approach. But even in situations where this is only partially true, we may still be able to benefit from the same concept. For instance, if lightness follows a pattern but hue doesn’t, we could split up the stylesheet like this:

<head>   <style>     :root {       --hue: 260;     }   </style>   <link rel="stylesheet" href="stylesheet-with-calculations-based-on-any-hue.css"> </head>

Supporting web components

Web components are an exciting (and evolving) concept. It’s enticing to think we can have encapsulated components that can be reused anywhere and theme them on a case-by-case basis. One component with many contexts!

We can use CSS variable theming with web components. It requires us to use a host-context() pseudo-selector. (Thanks to habemuscode for pointing this out to me!)

:host-context(body[data-theme="color-1"]) {   --shade-1: var(--outsideHSL); }

In summary…

Theming a website with CSS custom properties is much easier than the workaround approaches we’ve resorted to in the past. It’s more maintainable (one stylesheet), performant (less code), and opens up new possibilities (using JavaScript). Not to mention, CSS custom properties become even more powerful when they’re used with HSL colors and the calc() function.

We just looked at one example where we can change the color theme of a component based on the section where it is used. But again, there is much more opportunity here when we start to get into things like letting users change themes themselves – a topic that Chris explores in this article.

The post Creating Color Themes With Custom Properties, HSL, and a Little calc() appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

4 CSS Grid Properties (and One Value) for Most of Your Layout Needs

CSS Grid provides us with a powerful layout system for websites. The CSS-Tricks guide gives you a comprehensive overview of Grid’s properties with layout examples. What we’re going to do here is a reverse approach to show you the smallest possible set of grid properties you need to know to meet most of your layout needs.

These five properties will get you up and running:

  • display (for the grid value)
  • grid-template-columns
  • grid-gap
  • grid-auto-flow
  • grid-column / grid-row

Here’s how simple it is. Let’s assume you want to implement the following layout for small, medium and large screens.

Small and medium-sized screens
Large screen layout

This is the markup we’ll be working with:

 <!-- Stuff before -->  <nav class="container-nav">   <ul>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>     <li></li>   </ul> </nav>  <div class="container-main">   <section class="item item-type-a"></section>   <section class="item item-type-b"></section>   <section class="item item-type-b"></section>   <section class="item container-inner">     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>     <section class="item-inner"></section>   </section> </div>  <!-- Stuff after -->

If we apply a few baseline styles, this is what we get, which is already sufficient for small screens:

Now we can get into the grid properties!

Use display: grid to divide the page into independent layout containers

First, we need to determine which parts of the page should be aligned with grid layouts. It is possible to define a single grid layout for the whole page. However, for websites with a very complex structure (e.g. news websites), handling a large grid quickly becomes complicated to wrangle. In this case, I recommend breaking things down into several, independent grid containers.

Like this:

Where do you draw the line between what is and isn’t a grid? Here’s a personal rule of thumb I follow:

If the layout in a particular part of the page does not fit into the grid of an adjacent or surrounding part of the page, make that part its own grid container.

I have drawn the grid lines into the page section with the class .container-main in the following image You may notice that the section with the .container-inner class from the markup does not fit exactly into the grid of rows.

Here’s another possible layout where the small sections fit into the surrounding grid if a finer line raster is chosen. A separate grid container is not absolutely necessary here.

To kick this off, let’s .container-main into a grid container. This is the basic building block for CSS Grid — turning an element into a grid container with the display property:

.container-main {   display: grid;          }

We’ll want to do the same with our other grid containers:

.container-inner {   display: grid;          }  .container-nav {   display: grid;          }

Use grid-template-columns to define the required columns

Next, we’re going to define the number of columns we need in each grid container and how wide those columns should be. My guideline for the number of columns:  use the smallest common multiple of the maximum number of columns required for the different screen sizes.

How does that work? The .container-main element has a total of two columns on medium-sized screens. If we take that and multiply it by the number of columns on large screens (three), we get a total of six columns.

We can do the same for our navigation, the .container-inner element. There are three columns on medium-sized screens, which we multiple by one column on large screens to get a total of three columns.

The .container-nav element provides no number of columns. In this case, the grid system should automatically adjust the number of columns to the number of menu elements. It’s common to add or remove items in a navigation, and it’d be great if it responded accordingly, which is something grid can help us with a little later on.

OK, so we defined the number of columns for each grid container. Let’s use the grid-template-columns property to set those into place. But, first a couple of minor details:

  • The grid-template-columns property is only used on the grid container. In other words, you won’t find it being used (at least correctly) on a grid item inside the container.
  • The property accepts a bunch of different values that both define the number of columns and how wide they should be. The one we’re interested in here is the fractional (fr) unit. I’d highly suggest checking out Robin’s overview because it’s unique to grid and does an amazing job doing calculations to decide how grid elements fit inside a grid container.

We need six equal-width columns in .container-main. We can write that like this:

.container-main {   display: grid;   grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; }

Or, we can turn to the repeat() function to simplify it into something more readable:

.container-main {   display: grid;   grid-template-columns: repeat(6, 1fr); }

Let’s take that knowledge and apply it to our .container-inner element as well, which we decided needs three columns.

.container-inner {   display: grid;   grid-template-columns: repeat(3, 1fr); }

Use grid-gap to add spacing between grid items

By default, grid uses all the space it has in a grid container to fit in grid items. Having elements flush next to one another might be a design requirement, but not for the particular layout we’re making. We want some breathing room between things!

We have the grid-gap property for that. Again, this is a property that’s just for grid containers and what it does is create vertical and horizontal spacing between grid items. It’s actually a shorthand property that combines the vertical spacing powers of grid-row-gap and horizontal spacing powers of grid-column-gap. It’s handy that we’re able to break things out like that but, in times like this where we’re working with the same amount of spacing in each direction, the shorthand grid-gap is much nicer to write.

We want 20px of space between grid items in .container-main, 10px of space in .container-inner, and 5px of space in .container-nav. No problem! All it takes is a one-liner on each grid container.

.container-main{   display: grid;   grid-template-columns: repeat(6, 1fr);   grid-gap: 20px; }  .container-inner {   display: grid;   grid-template-columns: repeat(3, 1fr);   grid-gap: 10px; }  .container-nav {   display: grid;   grid-gap: 5px; }

Use grid-column and grid-row to determine the size of the individual grid items

Now it is time to put the layout into the shape we want it!

First is the grid-column property, which allows us to extend a grid item across n columns, where n is the number of columns to span. If you’re thinking this sounds an awful lot like the rowspan attribute that lets us extend cells across multiple rows in HTML tables, you wouldn’t be wrong.

It looks like this when we use it on a grid .item in our .container-main element, and on the .inner-item elements in .container-inner:

.item {   grid-column: span 6; }  .item-inner {   grid-column: span 3; }

What we’re saying here is that each item span six rows in our main container and three rows in our inner container — which is the total number of columns in each container.

An interesting thing about CSS Grid is that we are able to name the lines of the grid. They come with implicit names out of the box but naming them is a powerful way to distinguish between the starting and ending lines for each column on the track.

We can change the number of columns and rows the items should span at different breakpoints:

@media screen and (min-width: 600px) {   .item-type-b {     grid-column: span 3;   }    .item-inner {     grid-column: span 1;   } }  @media screen and (min-width: 900px) {   .item {     grid-column: span 2;     grid-row: span 2;   }    .item-type-b{     grid-row: span 1;   }    .item-inner{     grid-column: span 3;   } }

Using grid-auto-flow to control the placing of the elements

CSS Grid places elements one row after the other. This is why the result in our example looks like this at the moment:

A column-by-column placement can be achieved by setting the grid-auto-flow property to column (row is the default value). Our layout will profit from column-wise placement in two cases. First, it makes our menu items finally appear in a horizontal orientation. Secondly, it brings the elements of the container class into the desired grouping.

The final result

Conclusion: More or less specification?

The grid system allows us to work under the motto, “make as many specifications as necessary, but as few as possible.” We’ve only covered a few of the specifications necessary to turn elements into a CSS grid container and the items inside it into grid items for the sake of showing just how little you need to know to build even complex layouts with CSS Grid.

CSS Grid supports additional use cases where:

  • We want to make even fewer specifications in order to instead rely more on automatic positioning.
  • We want to make even more specifications in order to determine more details of the resulting layout.

If the first case applies, then it’s worth considering the following additional grid options:

  • When creating the grid with grid-template-columns, you can have the grid system automatically determine the width of individual columns with the auto keyword or adapt it to the existing content with the settings min-content, max-content, or fit-content.
  • You can let the grid system automatically determine the number of required columns with the help of repeat, auto-fill, auto-fit, and minmax. Even media queries can become redundant and these tools help make things flexible without adding more media queries.

Here are a couple of articles on the topic that I recommend: Becoming a CSS Grid Ninja! and Auto-Sizing Columns in CSS Grid: auto-fill vs. auto-fit.

If the second case applies, CSS Grid offers even more settings options for you:

  • You can explicitly specify the width of the columns in the unit of your choice (e.g. px or %) using the grid-template-columns property. In addition, the property grid-template-rows is available to define the number and width of rows, should there be a specific number of them. 
  • You can also define specific column or row numbers for positioning as values for grid-column and grid-row (or use the properties grid-column-start, grid-column-end, grid-row-start, or grid-row-end).

And we haven’t even gotten into CSS Grid alignment! Still, the fact that we can accomplish so much without even broaching that topic shows how powerful CSS Grid is.

The post 4 CSS Grid Properties (and One Value) for Most of Your Layout Needs appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

How many CSS properties are there?

Tomasz Łakomy posted a joke tweet about naming all the CSS attributes and Tejas Kumar replied with a joke answer, going as far as making an npm module. You can even run a terminal command to see them:

npx get-all-css-properties

You’ll get 259 of them. The source code uses the website quackit.com for the data, which I’d never heard of. 🤷‍♂️

I would have probably looked at MDN, where some quick querySelectorAll handiwork in the console yields a different number: 584. But ooops, that’s full of selectors, at-rules, and other stuff. Their reference only lists 72, but says it’s incomplete.

W3Schools lists 228 of them. HTML Dog lists 125. Our almanac has 176, and I know we omit stuff on purpose (e.g. we file margin-left under margin instead of making its own entry).

The horse’s mouth?

520 distinct property names from 66 technical reports and 66 editors’ drafts.

The post How many CSS properties are there? appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

7 Uses for CSS Custom Properties

, ,
[Top]

The Power (and Fun) of Scope with CSS Custom Properties

You’re probably already at least a little familiar with CSS variables. If not, here’s a two-second overview: they are really called custom properties, you set them in declaration blocks like --size: 1em and use them as values like font-size: var(--size);, they differ from preprocessor variables (e.g. they cascade), and here’s a guide with way more information.

But are we using them to their full potential? Do we fall into old habits and overlook opportunities where variables could significantly reduce the amount of code we write?

This article was prompted by a recent tweet I made about using CSS variables to create dynamic animation behavior.

Let’s look at a couple of instances where CSS variables can be used to do some pretty cool things that we may not have considered.

Basic scoping wins

The simplest and likely most common example would be scoped colors. And what’s our favorite component to use with color? The button. 😅

Consider the standard setup of primary and secondary buttons. Let’s start with some basic markup that uses a BEM syntax.

<button class="button button--primary">Primary</button> <button class="button button--secondary">Secondary</button>

Traditionally, we might do something like this to style them up:

.button {   padding: 1rem 1.25rem;   color: #fff;   font-weight: bold;   font-size: 1.25rem;   margin: 4px;   transition: background 0.1s ease; }  .button--primary {   background: hsl(233, 100%, 50%);   outline-color: hsl(233, 100%, 80%); }  .button--primary:hover {   background: hsl(233, 100%, 40%); }  .button--primary:active {   background: hsl(233, 100%, 30%); }  .button--secondary {   background: hsl(200, 100%, 50%);   outline-color: hsl(200, 100%, 80%); }  .button--secondary:hover {   background: hsl(200, 100%, 40%); }  .button--secondary:active {   background: hsl(200, 100%, 30%); }

See the Pen
Basic buttons
by Jhey (@jh3y)
on CodePen.

That’s an awful lot of code for something not particularly complex. We haven’t added many styles and we’ve added a lot of rules to cater to the button’s different states and colors. We could significantly reduce the code with a scoped variable.

In our example, the only differing value between the two button variants is the hue. Let’s refactor that code a little then. We won’t change the markup but cleaning up the styles a little, we get this:

.button {   padding: 1rem 1.25rem;   color: #fff;   font-weight: bold;   font-size: 1.25rem;   margin: 1rem;   transition: background 0.1s ease;   background: hsl(var(--hue), 100%, 50%);   outline-color: hsl(var(--hue), 100%, 80%);  } .button:hover {   background: hsl(var(--hue), 100%, 40%); }  .button:active {   background: hsl(var(--hue), 100%, 30%); }  .button--primary {   --hue: 233; }  .button--secondary {   --hue: 200; }

See the Pen
Refactoring styles with a scoped variable
by Jhey (@jh3y)
on CodePen.

This not only reduces the code but makes maintenance so much easier. Change the core button styles in one place and it will update all the variants! 🙌

I’d likely leave it there to make it easier for devs wanting to use those buttons. But, we could take it further. We could inline the variable on the actual element and remove the class declarations completely. 😲

<button class="button" style="--hue: 233;">Primary</button> <button class="button" style="--hue: 200;">Secondary</button>

Now we don’t need these. 👍

.button--primary {   --hue: 233; }  .button--secondary {   --hue: 200; }

See the Pen
Scoping w/ inline CSS variables
by Jhey (@jh3y)
on CodePen.

Inlining those variables might not be best for your next design system or app but it does open up opportunities. Like, for example, if we had a button instance where we needed to override the color.

button.button.button--primary(style=`--hue: 20;`) Overridden

See the Pen
Overridden with inline scope
by Jhey (@jh3y)
on CodePen.

Having fun with inline variables

Another opportunity is to have a little fun with it. This is a technique I use for many of the Pens I create over on CodePen. 😉

You may be writing straightforward HTML, but in many cases, you may be using a framework, like React or a preprocessor like Pug, to write your markup. These solutions allow you to leverage JavaScript to create random inline variables. For the following examples, I’ll be using Pug. Pug is an indentation-based HTML templating engine. If you aren’t familiar with Pug, do not fear! I’ll try to keep the markup simple.

Let’s start by randomizing the hue for our buttons:

button.button(style=`--hue: $ {Math.random() * 360}`) First

With Pug, we can use ES6 template literals to inline randomized CSS variables. 💪

See the Pen
Random inline CSS variable hues
by Jhey (@jh3y)
on CodePen.

Animation alterations

So, now that we have the opportunity to define random characteristics for an element, what else could we do? Well, one overlooked opportunity is animation. True, we can’t animate the variable itself, like this:

@keyframes grow {   from { --scale: 1; }   to   { --scale: 2; } }

But we can create dynamic animations based on scoped variables. We can change the behavior of animation on the fly! 🤩

Example 1: The excited button

Let’s create a button that floats along minding its own business and then gets excited when we hover over it.

Start with the markup:

button.button(style=`--hue: $ {Math.random() * 360}`) Show me attention

A simple floating animation may look like this:

@keyframes flow {   0%, 100% {     transform: translate(0, 0);   }   50% {     transform: translate(0, -25%);   } }

This will give us something like this:

See the Pen
The excited button foundation
by Jhey (@jh3y)
on CodePen.

I’ve added a little shadow as an extra but it’s not vital. 👍

Let’s make it so that our button gets excited when we hover over it. Now, we could simply change the animation being used to something like this:

.button:hover {   animation: shake .1s infinite ease-in-out; }  @keyframes shake {   0%, 100% {     transform: translate(0, 0) rotate(0deg);   }   25% {     transform: translate(-1%, 3%) rotate(-2deg);   }   50% {     transform: translate(1%, 2%) rotate(2deg);   }   75% {     transform: translate(1%, -2%) rotate(-1deg);   } }

And it works:

See the Pen
The excited button gets another keyframes definition
by Jhey (@jh3y)
on CodePen.

But, we need to introduce another keyframes definition. What if we could merge the two animations into one? They aren’t too far off from each other in terms of structure.

We could try:

@keyframes flow-and-shake {   0%, 100% {     transform: translate(0, 0) rotate(0deg);   }   25%, 75% {     transform: translate(0, -12.5%) rotate(0deg);   }   50% {     transform: translate(0, -25%) rotate(0deg);   } }

Although this works, we end up with an animation that isn’t quite as smooth because of the translation steps. So what else could we do? Let’s find a compromise by removing the steps at 25% and 75%.

@keyframes flow-and-shake {   0%, 100% {     transform: translate(0, 0) rotate(0deg);   }   50% {     transform: translate(0, -25%) rotate(0deg);   } }

It works fine, as we expected, but here comes the trick: Let’s update our button with some variables.

.button {   --y: -25;   --x: 0;   --rotation: 0;   --speed: 2; }

Now let’s plug them into the animation definition, along with the button’s animation properties.

.button {   animation-name: flow-and-shake;   animation-duration: calc(var(--speed) * 1s);   animation-iteration-count: infinite;   animation-timing-function: ease-in-out; }  @keyframes flow-and-shake {   0%, 100% {     transform: translate(calc(var(--x) * -1%), calc(var(--y) * -1%))       rotate(calc(var(--rotation) * -1deg));   }   50% {     transform: translate(calc(var(--x) * 1%), calc(var(--y) * 1%))       rotate(calc(var(--rotation) * 1deg));   } }

All is well. 👍

Let’s change those values when the button is hovered:

.button:hover {   --speed: .1;   --x: 1;   --y: -1;   --rotation: -1; }

See the Pen
The excited button with refactored keyframes & scoped variables
by Jhey (@jh3y)
on CodePen.

Nice! Now our button has two different types of animations but defined via one set of keyframes. 🤯

Let’s have a little more fun with it. If we take it a little further, we can make the button a little more playful and maybe stop animating altogether when it’s active. 😅

See the Pen
The Excited Button w/ dynamic animation 🤓
by Jhey (@jh3y)
on CodePen.

Example 2: Bubbles

Now that we’ve gone through some different techniques for things we can do with the power of scope, let’s put it all together. We are going to create a randomly generated bubble scene that heavily leverages scoped CSS variables.

Let’s start by creating a bubble. A static bubble.

.bubble {   background: radial-gradient(100% 115% at 25% 25%, #fff, transparent 33%),     radial-gradient(15% 15% at 75% 75%, #80dfff, transparent),     radial-gradient(100% 100% at 50% 25%, transparent, #66d9ff 98%);   border: 1px solid #b3ecff;   border-radius: 100%;   height: 50px;   width: 50px; }

We are using background with multiple values and a border to make the bubble effect — but it’s not very dynamic. We know the border-radius will always be the same. And we know the structure of the border and background will not change. But the values used within those properties and the other property values could all be random.

Let’s refactor the CSS to make use of variables:

.bubble {   --size: 50;   --hue: 195;   --bubble-outline: hsl(var(--hue), 100%, 50%);   --bubble-spot: hsl(var(--hue), 100%, 75%);   --bubble-shade: hsl(var(--hue), 100%, 70%);   background: radial-gradient(100% 115% at 25% 25%, #fff, transparent 33%),     radial-gradient(15% 15% at 75% 75%, var(--bubble-spot), transparent),     radial-gradient(100% 100% at 50% 25%, transparent, var(--bubble-shade) 98%);   border: 1px solid var(--bubble-outline);   border-radius: 100%;   height: calc(var(--size) * 1px);   width: calc(var(--size) * 1px); }

That’s a good start. 👍

See the Pen
Bubbles foundation
by Jhey (@jh3y)
on CodePen.

Let’s add some more bubbles and leverage the inline scope to position them as well as size them. Since we are going to start randomizing more than one value, it’s handy to have a function to generate a random number in range for our markup.

- const randomInRange = (max, min) => Math.floor(Math.random() * (max - min + 1)) + min

With Pug, we can utilize iteration to create a large set of bubbles:

- const baseHue = randomInRange(0, 360) - const bubbleCount = 50 - let b = 0 while b < bubbleCount   - const size = randomInRange(10, 50)   - const x = randomInRange(0, 100)   .bubble(style=`--x: $ {x}; --size: $ {size}; --hue: $ {baseHue}`)   - b++

Updating our .bubble styling allows us to make use of the new inline variables.

.bubble {   left: calc(var(--x) * 1%);   position: absolute;   transform: translate(-50%, 0); }

Giving us a random set of bubbles:

See the Pen
Adding bubbles
by Jhey (@jh3y)
on CodePen.

Let’s take it even further and animate those bubbles so they float from top to bottom and fade out.

.bubble {   animation: float 5s infinite ease-in-out;   top: 100%; }  @keyframes float {   from {     opacity: 1;     transform: translate(0, 0) scale(0);   }   to {     opacity: 0;     transform: translate(0, -100vh) scale(1);   } }

See the Pen
Bubbles rising together
by Jhey (@jh3y)
on CodePen.

That’s pretty boring. They all do the same thing at the same time. So let’s randomize the speed, delay, end scale and distance each bubble is going to travel.

- const randomInRange = (max, min) => Math.floor(Math.random() * (max - min + 1)) + min - const baseHue = randomInRange(0, 360) - const bubbleCount = 50 - let b = 0 while b < bubbleCount   - const size = randomInRange(10, 50)   - const delay = randomInRange(1, 10)   - const speed = randomInRange(2, 20)   - const distance = randomInRange(25, 150)   - const scale = randomInRange(100, 150) / 100   - const x = randomInRange(0, 100)   .bubble(style=`--x: $ {x}; --size: $ {size}; --hue: $ {baseHue}; --distance: $ {distance}; --speed: $ {speed}; --delay: $ {delay}; --scale: $ {scale}`)   - b++

And now, let’s update our styles

.bubble {   animation-name: float;   animation-duration: calc(var(--speed) * 1s);   animation-delay: calc(var(--delay) * -1s);   animation-iteration-count: infinite;   animation-timing-function: ease-in-out; }  @keyframes float {   from {     opacity: 1;     transform: translate(-50%, 0) scale(0);   }   to {     opacity: 0;     transform: translate(-50%, calc(var(--distance) * -1vh)) scale(var(--scale));   } }

And we will get this:

See the Pen
Random bubble scene using variable scope 😎
by Jhey (@jh3y)
on CodePen.

With around 50 lines of code, you can create a randomly generated animated scene by honing the power of the scope! 💪

That’s it!

We can create some pretty cool things with very little code by putting CSS variables to use and leveraging some little tricks.

I do hope this article has raised some awareness for the power of CSS variable scope and I do hope you will hone the power and pass it on 😎

All the demos in this article are available in this CodePen collection.

The post The Power (and Fun) of Scope with CSS Custom Properties appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Patterns for Practical CSS Custom Properties Use

I’ve been playing around with CSS Custom Properties to discover their power since browser support is finally at a place where we can use them in our production code. I’ve been using them in a number different ways and I’d love for you to get as excited about them as I am. They are so useful and powerful!

I find that CSS variables usage tends to fall into categories. Of course, you’re free to use CSS variables however you like, but thinking of them in these different categories might help you understand the different ways in which they can be used.

  • Variables. The basics, such as setting, a brand color to use wherever needed.
  • Default Values. For example, a default border-radius that can be overridden later.
  • Cascading Values. Using clues based on specificity, such as user preferences.
  • Scoped Rulesets. Intentional variations on individual elements, like links and buttons.
  • Mixins. Rulesets intended to bring their values to a new context.
  • Inline Properties. Values passed in from inline styles in our HTML.

The examples we’ll look at are simplified and condensed patterns from a CSS framework I created and maintain called Cutestrap.

A quick note on browser support

There are two common lines of questions I hear when Custom Properties come up. The first is about browser support. What browsers support them? Are there fallbacks we need to use where they aren’t supported?

The global market share that support the things we’re covering in this post is 85%. Still, it’s worth cross-referencing caniuse) with your user base to determine how much and where progressive enhancement makes sense for your project.

The second question is always about how to use Custom Properties. So let’s dive into usage!

Pattern 1: Variables

The first thing we’ll tackle is setting a variable for a brand color as a Custom Property and using it on an SVG element. We’ll also use a fallback to cover users on trailing browsers.

html {   --brand-color: hsl(230, 80%, 60%); }  .logo {   fill: pink; /* fallback */   fill: var(--brand-color); }

Here, we’ve declared a variable called --brand-color in our html ruleset. The variable is defined on an element that’s always present, so it will cascade to every element where it’s used. Long story short, we can use that variable in our .logo ruleset.

We declared a pink fallback value for trailing browsers. In the second fill declaration, we pass --brand-color into the var() function, which will return the value we set for that Custom Property.

That’s pretty much how the pattern goes: define the variable (--variable-name) and then use it on an element (var(--variable-name)).

See the Pen
Patterns for Practical Custom Properties: Example 1.0
by Tyler Childs (@tylerchilds)
on CodePen.

Pattern 2: Default values

The var() function we used in the first example can also provide default values in case the Custom Property it is trying to access is not set.

For example, say we give buttons a rounded border. We can create a variable — we’ll call it --roundness — but we won’t define it like we did before. Instead, we’ll assign a default value when putting the variable to use.

.button {   /* --roundness: 2px; */   border-radius: var(--roundness, 10px); }

A use case for default values without defining the Custom Property is when your project is still in design but your feature is due today. This make it a lot easier to update the value later if the design changes.

So, you give your button a nice default, meet your deadline and when --roundness is finally set as a global Custom Property, your button will get that update for free without needing to come back to it.

See the Pen
Patterns for Practical Custom Properties: Example 2.0
by Tyler Childs (@tylerchilds)
on CodePen.

You can edit on CodePen and uncomment the code above to see what the button will look like when --roundness is set!

Pattern 3: Cascading values

Now that we’ve got the basics under our belt, let’s start building the future we owe ourselves. I really miss the personality that AIM and MySpace had by letting users express themselves with custom text and background colors on profiles.

Let’s bring that back and build a school message board where each student can set their own font, background color and text color for the messages they post.

User-based themes

What we’re basically doing is letting students create a custom theme. We’ll set the theme configurations inside data-attribute rulesets so that any descendants — a .message element in this case — that consume the themes will have access to those Custom Properties.

.message {   background-color: var(--student-background, #fff);   color: var(--student-color, #000);   font-family: var(--student-font, "Times New Roman", serif);   margin-bottom: 10px;   padding: 10px; }  [data-student-theme="rachel"] {   --student-background: rgb(43, 25, 61);   --student-color: rgb(252, 249, 249);   --student-font: Arial, sans-serif; }  [data-student-theme="jen"] {   --student-background: #d55349;   --student-color: #000;   --student-font: Avenir, Helvetica, sans-serif; }  [data-student-theme="tyler"] {   --student-background: blue;   --student-color: yellow;   --student-font: "Comic Sans MS", "Comic Sans", cursive; }

Here’s the markup:

<section>   <div data-student-theme="chris">     <p class="message">Chris: I've spoken at events and given workshops all over the world at conferences.</p>   </div>   <div data-student-theme="rachel">     <p class="message">Rachel: I prefer email over other forms of communication.</p>   </div>   <div data-student-theme="jen">     <p class="message">Jen: This is why I immediately set up my new team with Slack for real-time chat.</p>   </div>   <div data-student-theme="tyler">     <p class="message">Tyler: I miss AIM and MySpace, but this message board is okay.</p>   </div> </section>

We have set all of our student themes using [data-student-theme] selectors for our student theme rulesets. The Custom Properties for background, color, and font will apply to our .message ruleset if they are set for that student because .message is a descendant of the div containing the data-attribute that, in turn, contains the Custom Property values to consume. Otherwise, the default values we provided will be used instead.

See the Pen
Patterns for Practical Custom Properties: Example 3.0
by Tyler Childs (@tylerchilds)
on CodePen.

Readable theme override

As fun and cool as it is for users to control custom styles, what users pick won’t always be accessible with considerations for contrast, color vision deficiency, or anyone that prefers their eyes to not bleed when reading. Remember the GeoCities days?

Let’s add a class that provides a cleaner look and feel and set it on the parent element (<section>) so it overrides any student theme when it’s present.

.readable-theme [data-student-theme] {   --student-background: hsl(50, 50%, 90%);   --student-color: hsl(200, 50%, 10%);   --student-font: Verdana, Geneva, sans-serif; }
<section class="readable-theme">   ... </section>

We’re utilizing the cascade to override the student themes by setting a higher specificity such that the background, color, and font will be in scope and will apply to every .message ruleset.

See the Pen
Patterns for Practical Custom Properties: Example 3.1
by Tyler Childs (@tylerchilds)
on CodePen.

Pattern 4: Scoped rulesets

Speaking of scope, we can scope Custom Properties and use them to streamline what is otherwise boilerplate CSS. For example, we can define variables for different link states.

a {   --link: hsl(230, 60%, 50%);   --link-visited: hsl(290, 60%, 50%);   --link-hover: hsl(230, 80%, 60%);   --link-active: hsl(350, 60%, 50%); }  a:link {   color: var(--link); }  a:visited {   color: var(--link-visited); }  a:hover {   color: var(--link-hover); }  a:active {   color: var(--link-active); }
<a href="#">Link Example</a>

Now that we’ve written out the Custom Properties globally on the <a> element and used them on our link states, we don’t need to write them again. These are scoped to our <a> element’s ruleset so they are only set on anchor tags and their children. This allows us to not pollute the global namespace.

Example: Grayscale link

Going forward, we can control the links we just created by changing the Custom Properties for our different use cases. For example, let’s create a gray-colored link.

.grayscale {   --link: LightSlateGrey;   --link-visited: Silver;   --link-hover: DimGray;   --link-active: LightSteelBlue; }
<a href="#" class="grayscale">Link Example</a>

We’ve declared a .grayscale ruleset that contains the colors for our different link states. Since the selector for this ruleset has a greater specificity then the default, these variable values are used and then applied to the pseudo-class rulesets for our link states instead of what was defined on the <a> element.

See the Pen
Patterns for Practical Custom Properties: Example 4.0
by Tyler Childs (@tylerchilds)
on CodePen.

Example: Custom links

If setting four Custom Properties feels like too much work, what if we set a single hue instead? That could make things a lot easier to manage.

.custom-link {   --hue: 30;   --link: hsl(var(--hue), 60%, 50%);   --link-visited: hsl(calc(var(--hue) + 60), 60%, 50%);   --link-hover: hsl(var(--hue), 80%, 60%);   --link-active: hsl(calc(var(--hue) + 120), 60%, 50%); }  .danger {   --hue: 350; }
<a href="#" class="custom-link">Link Example</a> <a href="#" class="custom-link danger">Link Example</a>

See the Pen
Patterns for Practical Custom Properties: Example 4.1
by Tyler Childs (@tylerchilds)
on CodePen.

By introducing a variable for a hue value and applying it to our HSL color values in the other variables, we merely have to change that one value to update all four link states.

Calculations are powerful in combination with Custom Properties since they let
your styles be more expressive with less effort. Check out this technique by Josh Bader where he uses a similar approach to enforce accessible color contrasts on buttons.

Pattern 5: Mixins

A mixin, in regards to Custom Properties, is a function declared as a Custom Property value. The arguments for the mixin are other Custom Properties that will recalculate the mixin when they’re changed which, in turn, will update styles.

The custom link example we just looked at is actually a mixin. We can set the value for --hue and then each of the four link states will recalculate accordingly.

Example: Baseline grid foundation

Let’s learn more about mixins by creating a baseline grid to help with vertical rhythm. This way, our content has a pleasant cadence by utilizing consistent spacing.

.baseline, .baseline * {   --rhythm: 2rem;   --line-height: var(--sub-rhythm, var(--rhythm));   --line-height-ratio: 1.4;   --font-size: calc(var(--line-height) / var(--line-height-ratio)); }  .baseline {   font-size: var(--font-size);   line-height: var(--line-height); }

We’ve applied the ruleset for our baseline grid to a .baseline class and any of its descendants.

  • --rhythm: This is the foundation of our baseline. Updating it will impact all the other properties.
  • --line-height: This is set to --rhythm by default, since --sub-rhythm is not set here.
  • --sub-rhythm: This allows us to override the --line-height — and subsequently, the --font-size — while maintaining the overall baseline grid.
  • --line-height-ratio: This helps enforce a nice amount of spacing between lines of text.
  • --font-size: This is calculated by dividing our --line-height by our --line-height-ratio.

We also set our font-size and line-height in our .baseline ruleset to use the --font-size and --line-height from our baseline grid. In short, whenever the rhythm changes, the line height and font size change accordingly while maintaining a legible experience.

OK, let’s put the baseline to use.

Let’s create a tiny webpage. We’ll use our --rhythm Custom Property for all of the spacing between elements.

.baseline h2, .baseline p, .baseline ul {   padding: 0 var(--rhythm);   margin: 0 0 var(--rhythm); }  .baseline p {   --line-height-ratio: 1.2; }  .baseline h2 {   --sub-rhythm: calc(3 * var(--rhythm));   --line-height-ratio: 1; }  .baseline p, .baseline h2 {   font-size: var(--font-size);   line-height: var(--line-height); }  .baseline ul {   margin-left: var(--rhythm); }
<section class="baseline">   <h2>A Tiny Webpage</h2>   <p>This is the tiniest webpage. It has three noteworthy features:</p>   <ul>     <li>Tiny</li>     <li>Exemplary</li>     <li>Identifies as Hufflepuff</li>   </ul> </section>

We’re essentially using two mixins here: --line-height and --font-size. We need to set the properties font-size and line-height to their Custom Property counterparts in order to set the heading and paragraph. The mixins have been recalculated in those rulesets, but they need to be set before the updated styling will be applied to them.

See the Pen
Patterns for Practical Custom Properties: Example 5.0
by Tyler Childs (@tylerchilds)
on CodePen.

Something to keep in mind: You probably do not want to use the Custom Property values in the ruleset itself when applying mixins using a wildcard selector. It gives those styles a higher specificity than any other inheritance that comes along with the cascade, making them hard to override without using !important.

Pattern 6: Inline properties

We can also declare Custom Properties inline. Let’s build a lightweight grid system demonstrate.

.grid {   --columns: auto-fit;    display: grid;   gap: 10px;   grid-template-columns: repeat(var(--columns), minmax(0, 1fr)); }
<div class="grid">   <img src="https://www.fillmurray.com/900/600" alt="Bill Murray" />   <img src="https://www.placecage.com/900/600" alt="Nic Cage" />   <img src="https://www.placecage.com/g/900/600" alt="Nic Cage gray" />   <img src="https://www.fillmurray.com/g/900/600" alt="Bill Murray gray" />   <img src="https://www.placecage.com/c/900/600" alt="Nic Cage crazy" />   <img src="https://www.placecage.com/gif/900/600" alt="Nic Cage gif" /> </div>

By default, the grid has equally sized columns that will automatically lay themselves into a single row.

See the Pen
Patterns for Practical Custom Properties: Example 6.0
by Tyler Childs (@tylerchilds)
on CodePen.

To control the number of columns we can set our --columns Custom Property
inline on our grid element.

<div class="grid" style="--columns: 3;">   ... </div>

See the Pen
Patterns for Practical Custom Properties: Example 6.1
by Tyler Childs (@tylerchilds)
on CodePen.


We just looked at six different use cases for Custom Properties — at least ones that I commonly use. Even if you were already aware of and have been using Custom Properties, hopefully seeing them used these ways gives you a better idea of when and where to use them effectively.

Are there different types of patterns you use with Custom Properties? Share them in the comments and link up some demos — I’d love to see them!

If you’re new to Custom Properties are are looking to level up, try playing around with the examples we covered here, but add media queries to the mix. You’ll see how adaptive these can be and how many interesting opportunities open up when you have the power to change values on the fly.

Plus, there are a ton of other great resources right here on CSS-Tricks to up your Custom Properties game in the Custom Properties Guide.

See the Pen
Thank you for Reading!
by Tyler Childs (@tylerchilds)
on CodePen.

The post Patterns for Practical CSS Custom Properties Use appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Managing Multiple Backgrounds with Custom Properties

One cool thing about CSS custom properties is that they can be a part of a value. Let’s say you’re using multiple backgrounds to pull off a a design. Each background will have its own color, image, repeat, position, etc. It can be verbose!

You have four images:

body {      background-position:     top 10px left 10px,     top 10px right 10px,     bottom 10px right 10px,     bottom 10px left 10px;      background-repeat: no-repeat;      background-image:     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-left.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-right.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-right.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-left.svg);    }

You want to add a fifth in a media query:

@media (min-width: 1500px) {   body {     /* REPEAT all existing backgrounds, then add a fifth. */   } }

That’s going to be super verbose! You’ll have to repeat each of those four images again, then add the fifth. Lots of duplication there.

One possibility is to create a variable for the base set, then add the fifth much more cleanly:

body {   --baseBackgrounds:      url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-left.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-right.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-right.svg),     url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-left.svg);    background-position:     top 10px left 10px,     top 10px right 10px,     bottom 10px right 10px,     bottom 10px left 10px;      background-repeat: no-repeat;      background-image: var(--baseBackgrounds); } @media (min-width: 1500px) {   body {     background-image:        var(--baseBackgrounds),       url(added-fifth-background.svg);   } }

But, it’s really up to you. It might make more sense and be easier manage if you made each background image into a variable, and then pieced them together as needed.

body {   --bg1: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-left.svg);   --bg2: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-right.svg);   --bg3: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-right.svg);   --bg4: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-left.svg);   --bg5: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-left.svg);      background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4); } @media (min-width: 1500px) {   body {     background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4), var(--bg5);   } }

Here’s a basic version of that, including a supports query:

See the Pen
Multiple BGs with Custom Properties
by Chris Coyier (@chriscoyier)
on CodePen.

Dynamically changing just the part of a value is a huge strength of CSS custom properties!

Note, too, that with backgrounds, it might be best to include the entire shorthand as the variable. That way, it’s much easier to piece everything together at once, rather than needing something like…

--bg_1_url: url(); --bg_1_size: 100px; --bg_1_repeat: no-repeat; /* etc. */

It’s easier to put all of the properties into shorthand and use as needed:

body {     --bg_1: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-left.svg) top 10px left 10px / 86px no-repeat;   --bg_2: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-top-right.svg) top 10px right 10px / 86px no-repeat;   --bg_3: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-right.svg) bottom 10px right 10px / 86px no-repeat;   --bg_4: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/angles-bottom-left.svg) bottom 10px left 10px  / 86px no-repeat;        background:     var(--bg_1), var(--bg_2),var(--bg_3),var(--bg_4); }

Like this.

The post Managing Multiple Backgrounds with Custom Properties appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

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

[Top]

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]