Tag: patterns

On Type Patterns and Style Guides

Over the last six years or so, I’ve been using these things I’ve been calling “type patterns” in my web design work, and they’ve worked out pretty well for me. I’ll dig into what they are and how they can make their way into CSS, and maybe the idea will click with you too and help with your day-to-day typography needs.

If you’ve used print design desktop software like QuarkXPress, Adobe InDesign, or CorelDraw, then imagine this idea is an HTML/CSS translation of “paragraph styles.”

When designing a book (that spans hundreds of pages), you might want to change something about the heading typography across the whole book (on the fly). You would define how a certain piece of typography behaves in one central place to be applied across the entire project (a book, in our example). You need control of the patterns.

Most programs use this naming style, but their user interfaces vary a little.

When you pull up the pane, there’s usually a “base” paragraph style that all default text belongs to. From there, you can create as many as you want. Paragraph styles are for “block” level-like elements, and character styles are for “inline” level-like elements, such as bold or unique spans.

The user interface specifics shouldn’t matter — but you can see that there are a lot of controls to define how this text behaves visually. Under the hood, it’s just key: value pairs, which is just like CSS property: value pairs

h1 {   font-family: "Helvetica Neue", sans-serif;    font-size: 20px;   font-weight: bold;   color: fuchsia; }

Once defined, the styles can be applied to any piece of text. The little + (next to the paragraph style name below) in this case, means that the style definition has changed.

If you want to apply those changes to everything with that paragraph style, then you can “redefine” the style and it will apply project-wide.

When I say it like that, it might make you think: that’s what a CSS class is.

But things are a little more complicated for a website. You never know what size your website will be displayed at (it could be small, like on a mobile device, or giant, like on a desktop monitor, or even on monochrome tablet, who knows), so we need to be contextual with those classes and have then change based on their context.

Styles change as the context changes.

The bare minimum of typographic control

In your very earliest days as a developer, you may have been introduced to semantic HTML, like this:

<h1>Here's some HTML stuff. I'm a heading level 1</h1> <p>And some more. I'm a paragraph.</p>  <h2>This is a heading level 2</h2> <p>And some more pragraph stuff.</p>

And that pairs with CSS that targets those elements and applies styles, like this:

h1 {   font-size: 50px; /* key: value pairs */   color: #ff0066; }  h2 {   font-size: 32px;   color: rgba(0,0,0,.8); }  p {   font-size: 16px;   color: deepskyblue;   line-height: 1.5; }

This works!

You can write rules that target the headers and style them in descending order, so they are biggest > big > medium, and so on.

Headers also already have some styles that we accept as normal, thanks to User Agent styles (i.e. default styles applied to HTML by the browser itself). They are meant to be helpful. They add things like font-weight and margin to the headers, as well as collapsing margins. That way — without any CSS at all — we can rest assured we get at least some basic styling in place to establish a hierarchy. This is beginner-friendly, fallback-friendly… and a good thing!

As you build more complex sites, things get more complicated

You add more pages. More modules. More components. Things start to get more complex. You might start out by adding unique classes and styles for every single little thing, but it’ll catch up to you.

First, you start having classes for special situations:

<h1 class="page-title">   Be <span class='super-ultra-magic-rainbow'>excellent</span> to each other </h1>  <p class="special-mantra">Party on, <em>dudes</em>.</p>  <p>And yeah. I'm just a regular paragraph.</p>

Then, you start having classes everywhere (most CSS methodologies even encourage this):

<header class="site-header">   <h1 class="page-title">     Be <span class='ultra-magic-rainbow'>excellent</span> to each other   </h1> </header>  <main class="page-content">   <section class="welcome">     <h2 class="special-mantra">Party on <em>dudes</em></h2>      <p class="regular-paragraph">And yeah. I'm just regular</p>   </section> </main>

Newcomers will try and work around the default font sizes and collapsing margins if they don’t feel confident resetting them.

This is where people start trying out margin-top: -20px… and then stuff gets whacky. As you keep writing more rules to wrangle things in, it will feel like you are “fixing” things instead of declaring how you actually want them to work. It can quickly feel like you are “fighting” the CSS cascade when you’re unaware of the browser’s User Agent styles.

A real-world example

Imagine you’re at your real job and your boss (or the visual designer) gives you this “pixel perfect” Adobe Photoshop document. There are a bunch of colors, layout, and typography.

You open up Photoshop and start to poke around, but there are so many pages and so many different type styles that you’ll need to take inventory and gather what styles can be combined or used in combination.

Would you believe that there are 12 different sizes of type on this page? There’s possibly even more if you also take the line-height into consideration.

It feels great to finish a visual layout and hand it off. However, I can’t tell you how many full days I’ve spent trying to figure out what the heck is happening in a Photoshop document. For example, sometimes small-screens aren’t taken into consideration at all; and when they are, the patterns you find aren’t always shared by each group as they change for different screen types. Some fonts start at 16px and go up to 18px, while others go up to 19px and become italic. How can spot context changes in a static mockup?

Sometimes this is with fervent purpose; other times the visual designer is just going on feel and is happy to round things up and down to create reusable patterns. You’ll have to talk to them about it. But this article is advocating that we talk about it much earlier in the process.

You might get a style guide to reference. But even that might not be specific enough to identify contexts.

Let’s zoom in on one of those guidelines:

We get more content direction than we do behavior of the content in different contexts.

You may even get a formal, but generic, style guide with no pixel sizes or notes on varying screen sizes at all!

Don’t get me wrong: this sort of thing is defintely a nice thought, and it might even be useful for others, like in some client meeting or something. But, as far as front-end development goes, it’s more confusing than helpful. I’ve received very thorough style guides that looked nice and gave lots of excellent guidelines for things like font sizes, but are completely mismatched with the accompanying Photoshop document. On the other end of the spectrum, there are style guides that have unholy amounts of specifics for every type of heading and combination you could ever imagine — and more.

It’s hard to parse this stuff, even with the best of intentions!

Early in your development career, you’d probably assume it’s your job to “figure it out” and get to work, writing down all the pixels and trying your best to make sense of it. Go getem!

But, as you start coding all the specifics, things can get a little overwhelming with the amount of duplication going on. Just look at all the repeated properties going on here:

.blog article p {   font-family: 'Georgia', serif;   font-size: 17px;   line-height: 1.4;   letter-spacing: 0.02em;   margin-bottom: 10px; }  .welcome .main-message {   font-family: 'Georgia', serif;   font-size: 17px;   line-height: 1.4;   letter-spacing: 0.02em;   margin-bottom: 20px; }  @media (min-width; 700px) {   .welcome .main-message {     font-size: 18px;   } }  .welcome .other-thing {   font-family: 'Georgia', serif;   font-size: 17px;   line-height: 1.4;   letter-spacing: 0.02em;   margin-bottom: 20px; }  .site-footer .link list a {   font-family: 'Georgia', serif;   font-size: 17px;   line-height: 1.4;   letter-spacing: 0.02em;   margin-bottom: 20px; }

You might take the common declarations and apply them to the body instead. In smaller projects, that might even be a good way to go. There are ways to use the cascade to your advantage, and others that seem to tie too many things together. Just like in an Object Oriented programming language, you don’t necessarily want everything inheriting everything.

body {   font-family: 'Georgia', serif;   font-size: 17px;   line-height: 1.4;   letter-spacing: 0.02em; }

Things will work out OK. Most of the web was built like this. We’re just looking for something even better.

Dealing with design revisions

One day, there will be a meeting. In that meeting, you’ll find out that the client and the visual designer decided to change a bunch of the typography. Now you need to go back and change it in 293 places in the CSS file. If you get paid by the hour, that might be great!

As you begin to adjust the rules, things will start to conflict. That rule that worked for two things now only works for the one. Or you’ll notice patterns that could now be used in many more places than before. You may even be tempted to just totally delete the CSS and start over! Yikes!

I won’t write it out here, but you’ll try a bunch of different things over time, and people usually come to the conclusion that you can create a class — and add it to the element instead of duplicating rules/declarations for every element. You’ll go even further to try and pull patterns out of the visual designer’s documents. (You might even round a few 19px down to 18px without telling them…)

.standard-text { /* or something */   font-family: serif;   font-size: 16px; /* px: up for debate */   line-height: 1.4; /* no unit: so it's relative to the font-size */   letter-spacing: 0.02em; /* em: so it's relative to the font-size */ }  .heading-1 {   font-family: sans-Serif;   font-size: 30px;   line-height: 1.5;   letter-spacing: 0.03em; }  .medium-heading {   font-family: sans-Serif;   font-size: 24px;   line-height: 1.3;   letter-spacing: 0.04em; }

Then you’d apply the class to anything that needs it.

<header class="site-header">   <h1 class="page-title heading-1">     Be <mark>excellent</mark> to each other   </h1> </header>  <main class="page-content">   <section class="welcome">     <h2 class="medium-heading">Party on <em>dudes</em></h2>      <p class="standard-text">And yeah. I'm just regular</p>   </section> </main>

This way of doing things can be really helpful for teams that have people of all skill levels changing the HTML. You can plug and play with these CSS classes to get the style you want, even if you’re the new intern.

It’s really helpful to separate the idea of “layout” elements (structure/parents) and the idea of “modules” or “components.” In this way, we’re treating the pieces of text as lower level components.

The key is to keep the typography separate from the layout. You don’t want all .medium-heading elements to have the same margins or colors. It’s going to depend on where they are. This way you are styling based on context. You aren’t ‘using’ the cascade necessarily, but you also aren’t fighting it because you keep the techniques separate.

.site-header {   padding: 20px 0; }  .welcome .medium-heading { /* the context — not the type-pattern */   margin-bottom: 10px; }

This is keeping things reasonable and tidy. This technique is used all over the web.

Working with a CMS

Great, but what about situations where you can’t change the HTML?

You might just be typing up a quick CodePen or a business-card site. In that case, these concerns are going to seem like overkill. On the other hand, you might be working with a CMS where you aren’t sure what is going to happen. You might need to plan for anything and everything that could get thrown at you. In those cases, you’re unable to simply add classes to individual elements. You’re likely to get a dump of HTML from some templating language.

<?php echo getContent()?> <?=getContent()?> $ {data.content} {{model.cmsContent}}

So, if you can’t work with the HTML what can you do?

<article class="post cms-blog-dump">   <h1>Talking type-patterns on CSS-tricks</h1>   <p>Intoduction paragraph - and we'd like to style this with a slightly different size font then the next (normal) paragraphs</p>   <h2>Some headings</h2>   <h2>And maybe someone accidentally puts 2 headings in a row</h2>   <ol>     <li>and some <strong>list</strong></li>     <li>and here</li>   </ol>    <p>Or if a blog post is too boring - then think of a list of bands on an event site. You never know how many there will be or which ones are headlining, so you have to write rules that will handle whatever happens. </article>

You don’t have any control over this markup, so you won’t be able to add classes, meaning that the cool plug-and-play classes you made aren’t going to work! You might just copy and paste them into some larger .article { } class that defines the rules for a kitchen sink. That could work.

What other tools are there to play with?

Mixins

If you could create some reusable concept of a “type pattern” with Sass, then you could apply those in a similar way to how the classes work.

@mixin my-useful-rule { /* define the mixin */   background-color: blue;   color: lime; }  .thing {   @include my-useful-rule(); /* employ the mixin */ }  /* This compiles to: */ .thing {   background-color: blue;   color: lime; } /* (just so that we're on the same page) */

Less, Sass, Stylus and other CSS preprocessors all have their own syntax for this. I’m going to use Sass/SCSS in these examples because it is the most common at the time of writing.

@mixin standard-type() { /* define the mixin */   font-family: Serif;   font-size: 16px;   line-height: 1.4;   letter-spacing: 0.02em; }  .context .thing {   @include standard-type(); /* employ it in context */ }

You can use heading-1() and heading-2() and a lot of big-name style guides do this. But what if you want to use those type styles on something that isn’t a “heading”? I personally don’t end up connecting the headings with “size” and I use the patterns in all sorts of different places. Sometimes my headings are “mean” and “stout.” They can be piercing red and uppercase with the same x-height as the paragraph text.

Instead, I define the visual styles in association with how I want the “voice” of the content to come across. This also helps the team discuss “tone” and other content strategy stuff across disciplines.

For example, in Jason Santa Maria’s book, On Web Typography, he talks about “type for a moment” and “type to live with.” There’s type to grab your attention and break up the page, and then those paragraphs to settle into. Instead of .standard-text or .normal-font, I’ve been enjoying the idea of organizing styles by voice. This is all that type that a user should spend time consuming. It’s what I’d likely use for most paragraphs and lists, and I won’t set it on the body.

@mixin calm-voice() { /* define the mixin */   font-family: Serif;   font-size: 16px;   line-height: 1.4;   letter-spacing: 0.02em; }  @mixin loud-voice() {   font-family: Sans-Serif;   font-size: 30px;   line-height: 1.5;   letter-spacing: 0.03em; }  @mixin attention-voice() {   font-family: Sans-Serif;   font-size: 24px;   line-height: 1.3;   letter-spacing: 0.04em; }

This idea of “voices” helps me keep things meaningful because it requires you to name things by the context. The name heading-1b, for example, doesn’t help me connect to the content to any sort of storytelling or to the other people on the team.

Now to style the mystery article. I’ll be using SCSS syntax here:

article {   padding: 20px 0;   h1 {     @include loud-voice();     margin-bottom: 20px;   }   h2 {     @include attention-voice();     margin-bottom: 20px;   }   p {     @include calm-voice();     margin-bottom: 10px;   } }

Pretty, right?

But it’s not that easy, is it? No. It’s a little more complicated because you don’t know what might be above or below each other — or what might be left out, because articles aren’t always structured or organized the same. Those CMS authors can put whatever they want in there! Three <h3> elements in a row? You have to prepare for lots of possible outcomes.

/* Styles */ article {   padding: 20px 0;    h1 {     @include loud-voice();   }    h2 {     @include attention-voice();   }    p {     @include calm-voice();      &:first-of-type {       background: lightgreen;       padding: 1em;     }   }    ol {     @include styled-ordered-list();   }    * + * {     margin-top: 1em    } } 

To see the regular CSS you can always “View Compiled” in CodePen.

Some people are really happy with the lobotomized owl approach (* + *) but I usually end up writing explicit rules for “any <h2> that comes after a paragraph” and getting really detailed. After all, it’s the written content that everyone wants to read… and I really only need to dial it in one time in one place.

/* Slightly more filled out pattern */ @mixin calm-voice() {   font-family: serif;   font-size: 16px;   line-height: 1.4;   letter-spacing: 0.02em;   max-width: 80ch;    strong {     font-weight: 700;   }    em {     font-style: italic;   }    mark {     background-color: wheat;   }    sup {     /* maybe? */   }    a {     text-decoration: underline;     color: $ highlight;   }    @media (min-width: 600px) {     font-size: 17px;   } }

Stylus

It’s nice to think about the “ideal” workflow. What could browsers implement that would make this fun and play well with their future systems?

Here’s an example of the most stripped down preprocessor syntax:

calm-voice()   font-family: serif   font-size: 16px   line-height: 1.4   letter-spacing: 0.02em  article   h1     loud-voice()   h2     attention-voice()   p     calm-voice() 

I’ll be honest… I love Stylus. I love writing it, and I love using it for examples. It keeps people on their toes. It’s so fast to type in CodePen! If you already have your own little framework of styles like this, it’s insane how fast you can build UI. But! The tooling has fallen behind and at this point, I can’t recommend that anyone use it.

I only add it here because it’s important to dream. We have what we have, but what if you could invent a new way of writing it? That’s a crucial part of the conversation too. If you can’t describe what you want, you wont get it.

We’re here: Type Patterns

Can you see where all of this is going?

You can use these “patterns” or “mixins’ or “whatever” you want to call them and plug and play. It’s fun. And you can totally combine it with the utility class idea too (if you must).

.calm-voice {   @include calm-voice(); }
<p class="calm-voice">Welcome to this code snippet!</p>

Style guides

If you can start to share a common language and break down the barriers between “creatives” and “coders,” then everyone can work with these type patterns in mind from the start.

Sometimes you can simply publish a style guide as a “brand” subdomain or directly on the site, like at /style-guide. There are tons of these floating around on the web. The point is that some style guides are standalone, and others are built into the site itself. Wherever they go, they are considered “live” and they allow you to develop things in one place that take effect globally, and use the guide itself as a sort of artifact.

By building live style guides with type patterns as a core and shared concept, everyone will have more fun and save time trying to figure out what each other means. It’s not just for big companies either.

Just be mindful when looking at style guides for other organizations. Style guides serve different purposes depending on who is using them and how, so simply diving into someone else’s work could actually contribute more confusion.

Known unknowns

Sometimes you don’t know what the content will be. That means CMS stuff, but also logic. What if you have a list of bands and events and you are building a module full of conditional components? There might be one band… or five… or two co-headliners. The event might be cancelled!

When I was trying to work out some templating ideas for Ticketfly, I separated the concerns of layout and type patterns.

Variable sized font patterns

Some patterns change sizes at various breakpoints.

@mixin attention-voice() {   font-family: Serif;   font-size: 20px;   line-height: 1.4;   letter-spacing: 0.02em;   @media (min-width: 700px) {     font-size: 24px;   }   @media (min-width: 1100px) {     font-size: 30px;   } }

I used to do something like this and it had a few yucky side effects. For example, what if you plug and play based on the breakpoints and there are sizes that conflict or slip through?

clamp() and vmin units to the rescue!

@mixin attention-voice() {   font-family: Serif;   font-size: clamp(18px, 10vmin, 100px);   line-height: 1.4;   letter-spacing: 0.02em; }

Now, in theory, you could even jump between the patterns with no rub.

.context {   @include calm-voice();   @media (min-width: 840px) {     @include some-other-voice();   } }

But now you have to make sure that they both have the same properties and that they don’t conflict with or bleed through to others! And think about the new variable font options too. Sometimes you’ll want your heading to be a little less heavy on smaller screens or a little taller to work with the space.

Aren’t you duplicating style rules all over the place?

Yikes! You caught me. I care way more about making the authoring and maintaining process pleasurable than I care about CSS byte size. I’m conflicted though. I get it. But I also think that the solution should happen somewhere else in the pipeline. There’s a reason that we don’t write machine code by hand.

Sometimes you have to examine a programming pattern closely and really poke at it, trying it in every place you can to prove how useful it is. Humor me for a movement and look at how you’d use this type pattern and other mixins to style a common “card” interface.

In a way, type patterns are like the utility class style of Bootstrap or Tailwind. But these are human readable. The patterns are added in the CSS instead of the HTML. The concept is the same. I like to think that anyone could look at the living style guide and jump into a component and style it. What do you think?

It is creating more CSS though. Those kilobytes are stacking up. But I think we should work towards something ideal instead of just “possible.” We can probably build something that works this out at build time. I’ll have to learn more about the CSSOM and there are many new things coming down the pipeline that could make this possible without a preprocessor.

It’s bigger than just the CSS. It’s about the people.

Having a set of patterns for type in your project allows visual designers to focus on their magic. More and more, we are building fast and in the browser. Visual designers focus on feel and typography and color with simple frameworks, like Style Tiles. Then developers can organize the data, resource structures and layouts, and everyone can work at the same time. We can have clearer communication and shared understanding of the entire process. We are all UX designers.

When living style guides are created as a team, there’s a lot less need for pixel-pushing. Visual designers can actually spend more time thinking and trying ideas in prototypes, and less time mocking out unnecessary production art. This allows you to work on your brand as a whole and have one single source of truth. It even helps with really small sites, like this.

Gold Collective style guide

InDesign and Illustrator have always had “paragraph styles” and “character styles” for this reason, but they don’t take into account variable screen sizes.

Toss in a few padding type sizes/ratios, some colors and some line widths. It doesn’t have to really be “pixel perfect” but more of a collection of patterns that work together. Colors as variables and maybe some $ thick, $ thin, or $ pad*2 type conventions can help streamline design patterns.

You can find your inspiration in the graphics program, then jump straight to the live style guide. People of all backgrounds can start playing with the styles in a CodePen and dial them in across devices.

In the end, you’ll decide the details on real devices — together, as a team.


The post On Type Patterns and Style Guides appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,

CSS Background Patterns

Nice little tool from Jim Raptis: CSS Background Patterns. A bunch of easy-to-customize and copy-and-paste backgrounds that use hard stop CSS gradients to make classy patterns. Not quite as flexible as SVG backgrounds, but just as lightweight.

Like this:

Speaking of cool background gradient tricks, check out our Complete Guide to CSS Gradients that just went out today!

Direct Link to ArticlePermalink


The post CSS Background Patterns appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

,
[Top]

How to Work With WordPress Block Patterns

Just a little post I wrote up over at The Events Calendar blog. The idea is that a set of blocks can be grouped together in WordPress, then registered in a register_block_pattern() function that makes the group available to use as a “block pattern” in any page or post.

Block patterns are becoming upper-class citizens in the WordPress block editor. They were announced without much fanfare in WordPress 5.5 back in August, but have been given prominent real estate in the block inserter with its own tab next to blocks, including 10 or so default ones right out of the box.

Block patterns are sandwiched between Blocks and Reusable Blocks in the block inserter, which is a perfect metaphor for where it fits in the bigger picture of WordPress editing.

If the 5.6 Beta 3 release notes are any indication, then it looks like more patterns are on the way for default WordPress themes. And, of course, the block registration function has an unregister_block_pattern() companion should you need to opt out of any patterns.

What I find interesting is how the blocks ecosystem is evolving. We started with a set of default blocks that can be inserted into a post. We got reusable blocks that provide a way to assemble a group of blocks with consistent content across all pages of posts. Now we have a way to do the same, but in a much more flexible and editable way. The differences are subtle, but the use cases couldn’t be more different. We’ve actually been using reusable blocks here at CSS-Tricks for post explanations, like this:

We drop some text in here when we think there’s something worth calling out or that warrants a little extra explanation.

Any reusable block can be converted to a “regular” block. The styles are maintained but the content is not. That’s been our hack-y approach for speeding up our process around here, but now that block patterns are a thing, previous reusable blocks we’ve been using now make more sense as patterns.

Direct Link to ArticlePermalink


The post How to Work With WordPress Block Patterns appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis

You can create stripes in CSS. That’s all I thought about in terms of CSS background patterns for a long time. There’s nothing wrong with stripes; stripes are cool. They can be customized into wide and narrow bands, criss-crossed into a checked pattern, and played with in other ways using the idea of hard stops. But stripes can be boring, too. Too conventional, out of fashion, and sometimes even unpleasant.

Thankfully, we can conjure up far more background patterns than you can even imagine with CSS, with code that is similar in spirit to stripes.

Background patterns are images repeated across a background. They can be done by referencing an external image, like a PNG file, or can be drawn with CSS, which is traditionally done using CSS gradients. 

Linear gradients (and repeating linear gradients) for instance, are typically used for stripes. But there are other ways to create cool background patterns. Let’s see how we can use gradients in other ways and toss in other things, like CSS shapes and emoji, to spice things up.

Gradient patterns

There are three types of CSS gradients.

Linear (left), radial (center) and conic (right) gradients
  1. linear-gradient(): Colors flow from left-to-right, top-to-bottom, or at any angle you choose in a single direction.
  2. radial-gradient(): Colors start at a single point and emanate outward
  3. conic-gradient(): Similar in concept to radial gradients, but the color stops are placed around the circle rather than emanating from the center point.

I recommend checking out the syntax for all the gradients to thoroughly understand how to start and end a color in a gradient.

Radial gradient patterns

Let’s look at radial gradients first because they give us very useful things: circles and ellipses. Both can be used for patterns that are very interesting and might unlock some ideas for you!

background: radial-gradient(<gradient values>)

Here’s a pattern of repeating watermelons using this technique:

background:  	radial-gradient(circle at 25px 9px, black 2px, transparent 2px),  	radial-gradient(circle at 49px 28px, black 2px, transparent 2px),  	radial-gradient(circle at 38px 1px, black 2px, transparent 2px),  	radial-gradient(circle at 20px 4px, black 2px, transparent 2px),  	radial-gradient(circle at 80px 4px, black 2px, transparent 2px),  	radial-gradient(circle at 50px 10px, black 2px, transparent 2px),  	radial-gradient(circle at 60px 16px, black 2px, transparent 2px),  	radial-gradient(circle at 70px 16px, black 2px, transparent 2px),  	radial-gradient(ellipse at 50px 0, red 33px, lime 33px, lime 38px, transparent 38px)  	white; background-size: 100px 50px;

We start by providing a background size on the element then stack up the gradients inside it. An ellipse forms the green and red parts. Black circles are scattered across to represent the watermelon seeds. 

The first two parameters for a radial gradient function determine whether the gradient shape is a circle or an ellipse and the starting position of the gradient. That’s followed by the gradient color values along with the start and ending positions within the gradient.

Conic gradient patterns

Conic gradients create ray-like shapes. Like linear and radial gradients, conic gradients can be used to create geometric patterns.

background: conic-gradient(<gradient values>)
background:    conic-gradient(yellow 40deg, blue 40deg, blue 45deg, transparent 45deg),    conic-gradient(transparent 135deg, blue 135deg, blue 140deg, transparent 140deg) ; background-size: 60px 60px; background-color: white;

The rub with conic gradient is that it’s not supported in Firefox, at least at the time of writing. It’s always worth keeping an eye out for deeper support.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Firefox IE Edge Safari
69 No No 79 12.1

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
81 No 81 12.2-12.4

Emoji icon patterns

This is where things begin to get interesting. Rather than just using geometric patterns (as in gradients), we now use the organic shapes of emojis to create background patterns. 🎉 

It starts with emoji icons. 

Solid-color emoji patterns

We can create emoji icons by giving emojis a transparent color and text shadow.

color: transparent; text-shadow: 0 0 black;

Those icons can then be turned into an image that can be used as a background, using SVG.

<svg>   <foreignObject>     <!-- The HTML code with emoji -->   </foreignObject> </svg>

The SVG can then be referred by the background property using data URL

background: url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><!-- SVG code --></svg>");

And, voilá! We get something like this:

background:      url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><foreignObject width=%22100px%22 height=%22100px%22><div xmlns=%22http://www.w3.org/1999/xhtml%22 style=%22color:transparent;text-shadow: 0 0 %23e42100, -2px 2px 0 black;font-size:70px%22>🏄‍♀️</div></foreignObject></svg>"),      white;  background-size: 60px 60px; 

Other than emojis, it’s also possible to draw CSS shapes and use them as patterns. Emojis are less work, though. Just saying. 

Gradient-colored emoji patterns

Instead of using plain emoji icons, we can use gradient emoji icons. To do that, skip the text shadow on the emojis. Add a gradient background behind them and use background-clip to trim the gradient background to the shape of the emojis. 

color: transparent; background: linear-gradient(45deg, blue 20%, fuchsia); background-clip: text; /* Safari requires -webkit prefix */

Then, just as before, use the combination of SVG and data URL to create the background pattern.

Translucent-colored emoji patterns

This is same as using block colored emoji icons. This time, however, we take away the opaqueness of the colors by using rgba() or hsla() values for the text shadow. 

color: transparent; text-shadow: 20px 10px rgba(0, 255, 0, .3),               0 0 red;

SVG-text emoji patterns

We’ve already looked at all the working methods I could think of to create background patterns, but I feel like I should also mention this other technique I tried, which is not as widely supported as I’d hoped.

 I tried placing the emoji in an SVG <text> element instead of the HTML added using <foreignObject>. But I wasn’t able to create a solid shadow behind it in all the browsers.

background:    url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%221em%22 font-size=%2270%22 fill=%22transparent%22 style=%22text-shadow: 0 0 %23e42100, -2px 2px 5px black, 0 0 6px white; ;%22>🏄‍♀️</text></svg>") 

Just in case, I tried using CSS and SVG filters for the shadow as well, thinking that might work. It didn’t. I also tried using the stroke attribute, to at least create an outline for the emoji, but that didn’t work, either. 

CSS element() patterns

I didn’t think of SVG when I first thought of converting emoji icons or CSS shapes into background images. I tried CSS element(). It’s a function that directly converts an HTML element into an image that can be referenced and used. I really like this approach, but browser support is a huge caveat, which is why I’m mentioning it here at the end.

Basically, we can drop an element in the HTML like this:

<div id=snake >🐍</div>

…then pass it into the element() function to use like an image on other elements, like this:

background:    -moz-element(#snake), /* Firefox only */   linear-gradient(45deg, transparent 20px, blue 20px, blue 30px, transparent 30px)    white; background-size: 60px 60px; background-color: white;

Now that snake emoji is technically an image that we get to include in the pattern.

Again, browser support is spotty, making this approach super experimental.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Firefox IE Edge Safari
No 4* No No No

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
No 68* No No

In this method, the original emoji (or any CSS shape for that matter) used for the background pattern needs to render on screen for it to appear in the background pattern as well. To hide that original emoji, I used mix-blend-mode — it sort of masks out the original emoji in the HTML so it doesn’t show up on the page.


I hope you find the methods in this post useful in one way or another and learned something new in the process! Give them a try. Experiment with different emojis and CSS shapes because gradients, while cool and all, aren’t the only way to make patterns.. The background property takes multiple values, allowing us to think of creative ways to stack things.

The post Creative Background Patterns Using Gradients, CSS Shapes, and Even Emojis appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

Background Patterns, Simplified by Conic Gradients

For those who have missed the big news, Firefox now supports conic gradients!

Starting with Firefox 75, released on the April 7, we can go to about:config, look for the layout.css.conic-gradient.enabled flag and set its value to true (it’s false by default and all it takes to switch is double-clicking it).

Screenshot. Shows the Firefox URL bar at `about:config`, a search for 'conic' giving the `layout.css.conic-gradient.enabled` flag as the sole result and its value set to `true`.
Enabling conic gradients in Firefox 75+

With that enabled, now we can test our CSS including conic gradients in Firefox as well.

While some of the demos in this article work just fine when using a polyfill, some use CSS variables inside the conic gradient and therefore require native support for this feature.

One thing I particularly like about conic gradients is just how much they can simplify background patterns. So let’s take a few linear-gradient() patterns from the gallery created by Lea Verou about a decade ago and see how we can now simplify them with conic-gradient!

Pyramid

Screenshot. Shows the original pyramid pattern with the code that was used to create it.
The pyramid pattern

The pattern above uses four linear gradients:

background:   linear-gradient(315deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(45deg, transparent 75%, #d45d55 0) -10px 0,   linear-gradient(135deg, #a7332b 50%, transparent 0) 0 0,   linear-gradient(45deg, #6a201b 50%, #561a16 0) 0 0 #561a16; background-size: 20px 20px;

That’s quite a bit of CSS and perhaps even a bit intimidating. It’s not easy to just look at this and understand how it all adds up to give us the pyramid pattern. I certainly couldn’t do it. It took me a while to get it, even though gradients are one of the CSS features I’m most comfortable with. So don’t worry if you don’t understand how those gradients manage to create the pyramid pattern because, one, it is complicated and, two, you don’t even need to understand that!

Using conic-gradient(), we can now get the same result in a much simpler manner, with a single background layer instead of four!

What I like to do when coding repeating patterns is draw equidistant vertical and horizontal lines delimiting the rectangular boxes defined by the background-size. In this case, it’s pretty obvious we have square boxes and where their limits are, but it’s a really useful technique for more complex patterns.

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

By default, conic gradients start from 12 o’clock and go clockwise. However, in our case, we want to offset the start of the gradient by 45° in the clockwise direction and afterwards make every one of the four shades occupy a quarter (25%) of the available space around the midpoint of our square box.

SVG illustration. Shows how we place a conic gradient into a single pattern cell by rotating the gradient start point 45° in the clockwise (positive) direction.
A pattern cell with a conic gradient’s hard stops at every 25% starting from 45° w.r.t. the vertical axis (live).

This means our pyramid pattern can be reduced to:

$ s: 20px; background:   conic-gradient(from 45deg,      #561a16 25%,      #6a201b 0% 50%,      #a7332b 0% 75%,      #d45d55 0%)      50%/ #{$ s $ s};

Not only does the code look simpler, but we’ve also gone from 260 bytes to 103 bytes, reducing the code needed to get this pattern by more than half.

We’re using the double position syntax as that’s also well supported these days.

We can see it in action in the Pen below:

Checkerboard

Screenshot. Shows the original checkerboard pattern with the code that was used to create it.
The checkerboard pattern

This pattern above is created with two linear gradients:

background-color: #eee; background-image:   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px; background-position: 0 0, 30px 30px;

Let’s see how we can simplify this CSS when replacing these linear gradients with a conic one!

Just like in the previous case, we draw vertical and horizontal lines in order to better see the rectangles defined by the background-size.

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

Looking at the square highlighted in deeppink in the illustration above, we see that, in this case, our conic gradient starts from the default position at 12 o’clock. A quarter of it is black, the next quarter is dirty white and then we have repetition (the same black and then dirty white quarter slices once more).

SVG illustration. Shows how we place a conic gradient into a single pattern cell and then make it repeat after the 50% point.
A pattern cell with a conic gradient’s hard stops at every 25%, starting from the default at 12 o’clock and repeating after 50% (demo).

This repetition in the second half of the [0%, 100%] interval means we can use a repeating-conic-gradient(), which gives us the following code (bringing the compiled CSS from 263 bytes down to only 73 bytes – that’s reducing it by over 70%):

$ s: 60px; background:   repeating-conic-gradient(#000 0% 25%, #eee 0% 50%)      50%/ #{$ s $ s};

The Pen below shows it in action:

Diagonal checkerboard

Screenshot. Shows the original diagonal checkerboard pattern with the code that was used to create it.
The diagonal checkerboard pattern

Again, we have a pattern created with two linear gradients:

background-color: #eee; background-image:    linear-gradient(45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black),   linear-gradient(-45deg, black 25%, transparent 25%,      transparent 75%, black 75%, black); background-size: 60px 60px;

We draw horizontal and vertical lines to split this pattern into identical rectangles:

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells

What we now have is pretty much the same checkerbox pattern as before, with the sole difference that we don’t start from the default position at 12 o’clock, but from 45° in the clockwise direction.

If you’re having trouble visualising how simply changing the start angle can make us go from the previous pattern to this one, you can play with it in the interactive demo below:

Note that this demo does not work in browsers that have no native support for conic gradients.

This means our code looks as follows:

$ s: 60px; background:   repeating-conic-gradient(from 45deg,      #000 0% 25%, #eee 0% 50%)    50%/ #{$ s $ s};

We can see it in action below:

Again, not only is the code simpler to understand, but we’ve also gone from 229 bytes to only 83 bytes in the compiled CSS, reducing it by almost two-thirds!

Half-Rombes

Screenshot. Shows the original Half-Rombes pattern with the code that was used to create it.
The half-rombes pattern

This pattern was created with four linear gradients:

background: #36c; background:   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,   linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,   #36c; background-size: 15px 30px;

Just like in the previous cases, we draw equidistant vertical and horizontal lines in order to better see the repeating unit:

Annotated screenshot. Shows the rectangles (squares in this case) defined by the `background-size`.
Highlighting the pattern’s cells.

What we have here is a pattern that’s made up of congruent isosceles triangles (the angled edges are equal and the dark blue triangles are a reflection of the light blue ones) formed by the intersection of equidistant parallel lines that are either horizontal, angled clockwise, or the other way. Each of these three types of parallel lines is highlighted in the illustration below:

Illustration. Shows the equidistant parallel lines which create the pattern of isosceles triangles.
Parallel guides

Every pattern cell contains a full triangle and two adjacent triangle halves in the upper part, then a reflection of this upper part in the lower part. This means we can identify a bunch of congruent right triangles that will help us get the angles we need for our conic-gradient():

SVG illustration. Shows how we place a conic gradient into a single pattern cell by rotating the gradient start point by an angle β in the clockwise (positive) direction such that the 0% line goes through the top right corner and then all the other hard stops are either horizontal or going through the cell corners.
A pattern cell with a conic gradient’s hard stops such that they’re either horizontal or go through the cell corners, all starting from β w.r.t. the vertical axis (demo)

This illustration shows us that the gradient starts from an angle, β, away from the default conic gradient start point at 12 o’clock. The first conic slice (the top right half triangle) goes up to α, the second one (the bottom right dark triangle) up to 2·α, and the third one (the bottom light triangle) goes halfway around the circle from the start (that’s 180°, or 50%). The fourth one (the bottom left dark triangle) goes to 180° + α and the fifth one (the top left light triangle) goes to 180° + 2·α, while the sixth one covers the rest.

SVG illustration. Highlights the right triangle from where we can get α knowing the catheti and shows how we can then compute β.
Getting α and β (demo)

From the highlighted right triangle we get that:

tan(α) = (.5·h)/(.5·w) = h/w

Knowing the width (w) and height (h) of a pattern cell, we can get the angles α and β:

α = atan(h/w) β = 90° - α

It results in the pattern that’s generated by the following code:

$ w: 15px; $ h: 30px; $ a: atan($ h/$ w)*180deg/pi(); $ b: 90deg - $ a; $ c0: #36c; $ c1: #d6e0f5;  html {   background:      conic-gradient(from $ b,        $ c1 0% $ a,        $ c0 0% 2*$ a,        $ c1 0% 50%,        $ c0 0% 180deg + $ a,        $ c1 0% 180deg + 2*$ a,        $ c0 0%)      0 0/ #{$ w $ h}; }

This means going from 343 bytes to only 157 bytes in the compiled CSS. The result can be seen below:

You can tweak the pattern width ($ w) and height ($ h) in the Sass code in order to see how the pattern gets squished and stretched for different aspect ratios.

In the particular case where the angle between 2*$ a and 50% (or 180deg) is also $ a, it results that $ a is 60deg, our isosceles triangles are equilateral, and our gradient can be reduced to a repeating one (and under 100 bytes in the compiled CSS):

$ a: 60deg; $ b: 90deg - $ a; $ w: 15px; $ h: $ w*tan($ a); $ c0: #36c; $ c1: #d6e0f5;  html {   background:      repeating-conic-gradient(from $ b,        $ c1 0% $ a, $ c0 0% 2*$ a)      0 0/ #{$ w $ h} }

The live result can be seen below:

Bonus: Intersecting line backgrounds!

Screenshot. Shows the original intersecting lines pattern with the code that was used to create it.
Intersecting line background examples

While these are not repeating patterns, they’re examples of a situation where a single conic gradient achieves an effect that would have previously needed a bunch of linear ones.

What we have here is a conic-gradient() created starting from two straight lines intersecting within the rectangular box where we set the background.

SVG illustration. Shows a rectangular box and two random lines intersecting inside it. This intersection point (x,y) is the point the conic gradient goes around, while the gradient's start is from the angle β formed by the line segment closest to the top right corner with the vertical. The hard stops are at α, the angle between the start segment and the next one in clockwise order, at 50% and at 180° + α.
Bonus pattern structure (ldemo)

The gradient goes around the point of coordinates, x,y, where the two straight lines intersect. It starts from an angle, β, which is the angle of the line segment that’s closest to the top-right corner, then has hard stops at α, 50% (or 180°) and 180° + α.

If we want to have multiple elements with similar such patterns created with the help of different intersecting lines and different palettes, we have the perfect use case for CSS variables:

.panel {   background:      conic-gradient(from var(--b) at var(--xy),        var(--c0) var(--a), var(--c1) 0% 50%,        var(--c2) 0% calc(180deg + var(--a)), var(--c3) 0%); }

All we have to do is set the position (--xy), the start angle (--b), the first angle (--a) and the palette (--c0 through --c3).

.panel {   /* same as before */      &:nth-child(1) {     --xy: 80% 65%;      --b: 31deg;     --a: 121deg;      --c0: #be5128;     --c1: #ce9248;     --c2: #e4c060;     --c3: #db9c4e   }      /* similarly for the other panels */ }

Instead of hardcoding, we could also generate these values randomly or extract them from a data object with the help of a CSS or HTML preprocessor. In this second case, we’d set these custom properties inline, which is precisely what I did in the Pen below:

Since we’re using custom properties inside the conic gradients, this demo does not work in browsers that don’t support them natively.

Well, that’s it! I hope you’ve enjoyed this article and that it gives you some ideas about how conic gradients can make your life easier.

The post Background Patterns, Simplified by Conic Gradients appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

The Many Bad (and Good!) Patterns for Close Buttons

Manuel Matuzović details 10 bad HTML patterns for a close button. You know, stuff like this:

<a class="close" onclick="close()">×</a>

Why is that bad? There is no href there, so it really isn’t a link (close buttons aren’t links). Not to mention the missing href makes this “placeholder link” unfocusable. Plus, that symbol will be read as “multiplication” or “times”, which is not helpful (an “x” isn’t either).

What do you use instead?

There are plenty of good patterns too. If you prefer the visual look of a ×, then…

<button type="button">   <span class="sr-only">Close</span>   <span aria-hidden="true">×</span> </button>

…making sure you are accessibly hiding that close button.

Direct Link to ArticlePermalink

The post The Many Bad (and Good!) Patterns for Close Buttons appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

A Few Background Patterns Sites

If I need a quick background pattern to spruce something up, I often think of the CSS3 Patterns Gallery. Some of those are pretty intense but remember they are easily editable because they are just CSS. That means you could take these bold zags and chill them out.

My usual go-to through is Hero Patterns. They are also editable, but they already start from a pretty chill place, which is usually what I’m looking for from a pattern. They also happen to provide ones we’ve baked into the Assets Panel on CodePen for extra-easy access.

If you’re into SVG-based patterns (and who isn’t?) SVG Backgrounds has some extra clever ones. Looks like it’s gotten a nice design refresh lately, too, where the editable options are intuitive and the code is easy to copy. If you are a DIY type, remember SVG literally has a <pattern> element you can harness.

I’ve seen some new fun pattern sites lately though! One is the exceptionally deep Tartanify which has over 5,000 Scottish tartan patterns. Paulina Hetman even wrote about it for us.

Beautiful Dingbats has a very nice pattern generator as well that seems pretty newish. It’s got very fun controls to play with and easy output.

One that is really mind-blowing is Mazeletter. It’s a collection of nine fonts that are made to be infinitely tiling, so you essentially have unlimited pattern possibilities you can make from characters.

Just to end with a classic here… you can’t go wrong with a little noise.

The post A Few Background Patterns Sites appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

How We Created a Static Site That Generates Tartan Patterns in SVG

Tartan is a patterned cloth that’s typically associated with Scotland, particularly their fashionable kilts. On tartanify.com, we gathered over 5,000 tartan patterns (as SVG and PNG files), taking care to filter out any that have explicit usage restrictions.

The idea was cooked up by Sylvain Guizard during our summer holidays in Scotland. At the very beginning, we were thinking of building the pattern library manually in some graphics software, like Adobe Illustrator or Sketch. But that was before we discovered that the number of tartan patterns comes in thousands. We felt overwhelmed and gave up… until I found out that tartans have a specific anatomy and are referenced by simple strings composed of the numbers of threads and color codes.

Tartan anatomy and SVG

Tartan is made with alternating bands of colored threads woven at right angles that are parallel to each other. The vertical and horizontal bands follow the same pattern of colors and widths. The rectangular areas where the horizontal and vertical bands cross give the appearance of new colors by blending the original ones. Moreover, tartans are woven with a specific technique called twill, which results in visible diagonal lines. I tried to recreate the technique with SVG rectangles as threads here:

Let’s analyze the following SVG structure:

 <svg viewBox="0 0 280 280" width="280" height="280" x="0"  y="0" xmlns="http://www.w3.org/2000/svg">   <defs>     <mask id="grating" x="0" y="0" width="1" height="1">       <rect x="0" y="0" width="100%" height="100%" fill="url(#diagonalStripes)"/>     </mask>   </defs>   <g id="horizontalStripes">     <rect fill="#FF8A00" height="40" width="100%" x="0" y="0"/>         <rect fill="#E52E71" height="10" width="100%" x="0" y="40"/>     <rect fill="#FFFFFF" height="10" width="100%" x="0" y="50"/>     <rect fill="#E52E71" height="70" width="100%" x="0" y="60"/>        <rect fill="#100E17" height="20" width="100%" x="0" y="130"/>         <rect fill="#E52E71" height="70" width="100%" x="0" y="150"/>     <rect fill="#FFFFFF" height="10" width="100%" x="0" y="220"/>     <rect fill="#E52E71" height="10" width="100%" x="0" y="230"/>        <rect fill="#FF8A00" height="40" width="100%" x="0" y="240"/>   </g>   <g id="verticalStripes" mask="url(#grating)">     <rect fill="#FF8A00" width="40" height="100%" x="0" y="0" />       <rect fill="#E52E71" width="10" height="100%" x="40" y="0" />     <rect fill="#FFFFFF" width="10" height="100%" x="50" y="0" />     <rect fill="#E52E71" width="70" height="100%" x="60" y="0" />     <rect fill="#100E17" width="20" height="100%" x="130" y="0" />        <rect fill="#E52E71" width="70" height="100%" x="150" y="0" />     <rect fill="#FFFFFF" width="10" height="100%" x="220" y="0" />     <rect fill="#E52E71" width="10" height="100%" x="230" y="0" />        <rect fill="#FF8A00" width="40" height="100%" x="240" y="0" />   </g> </svg>

The horizontalStripes group creates a 280×280 square with horizontal stripes. The verticalStripes group creates the same square, but rotated by 90 degrees. Both squares start at (0,0) coordinates. That means the horizontalStripes are completely covered by the verticalStripes; that is, unless we apply a mask on the upper one.

<defs>   <mask id="grating" x="0" y="0" width="1" height="1">     <rect x="0" y="0" width="100%" height="100%" fill="url(#diagonalStripes)"/>   </mask> </defs>

The mask SVG element defines an alpha mask. By default, the coordinate system used for its x, y, width, and height attributes is the objectBoundingBox. Setting width and height to 1 (or 100%) means that the mask covers the verticalStripes resulting in just the white parts within the mask being full visible.

Can we fill our mask with a pattern? Yes, we can! Let’s reflect the tartan weaving technique using a pattern tile, like this:

In the pattern definition we change the patternUnits from the default  objectBoundingBox to userSpaceOnUse so that now, width and height are defined in pixels.

<svg width="0" height="0">   <defs>     <pattern id="diagonalStripes" x="0" y="0" patternUnits="userSpaceOnUse" width="8" height="8">       <polygon points="0,4 0,8 8,0 4,0" fill="white"/>       <polygon points="4,8 8,8 8,4" fill="white"/>     </pattern>       </defs>  </svg>

Using React for tartan weaving

We just saw how we can create a manual “weave” with SVG. Now let’s automatize this process with React. 

The SvgDefs component is straightforward — it returns the defs markup.

const SvgDefs = () => {   return (     <defs>       <pattern         id="diagonalStripes"         x="0"         y="0"         width="8"         height="8"         patternUnits="userSpaceOnUse"       >         <polygon points="0,4 0,8 8,0 4,0" fill="#ffffff" />         <polygon points="4,8 8,8 8,4" fill="#ffffff" />       </pattern>       <mask id="grating" x="0" y="0" width="1" height="1">         <rect           x="0"           y="0"           width="100%"           height="100%"           fill="url(#diagonalStripes)"         />       </mask>     </defs>   ) }

We will represent a tartan as an array of stripes. Each stripe is an object with two properties: fill (a hex color) and size (a number).

const tartan = [   { fill: "#FF8A00", size: 40 },   { fill: "#E52E71", size: 10 },   { fill: "#FFFFFF", size: 10 },   { fill: "#E52E71", size: 70 },   { fill: "#100E17", size: 20 },   { fill: "#E52E71", size: 70 },   { fill: "#FFFFFF", size: 10 },   { fill: "#E52E71", size: 10 },   { fill: "#FF8A00", size: 40 }, ]

Tartans data is often available as a pair of strings: Palette and Threadcount that could look like this:

// Palette O#FF8A00 P#E52E71 W#FFFFFF K#100E17  // Threadcount O/40 P10 W10 P70 K/10.

I won’t cover how to convert this string representation into the stripes array but, if you are interested, you can find my method in this Gist.

The SvgTile component takes the tartan array as props and returns an SVG structure.

const SvgTile = ({ tartan }) => {    // We need to calculate the starting position of each stripe and the total size of the tile   const cumulativeSizes = tartan     .map(el => el.size)     .reduce(function(r, a) {       if (r.length > 0) a += r[r.length - 1]       r.push(a)       return r     }, [])      // The tile size   const size = cumulativeSizes[cumulativeSizes.length - 1]    return (     <svg       viewBox={`0 0 $ {size} $ {size}`}       width={size}       height={size}       x="0"       y="0"       xmlns="http://www.w3.org/2000/svg"     >       <SvgDefs />       <g id="horizontalStripes">         {tartan.map((el, index) => {           return (             <rect               fill={el.fill}               width="100%"               height={el.size}               x="0"               y={cumulativeSizes[index - 1] || 0}             />           )         })}       </g>       <g id="verticalStripes" mask="url(#grating)">         {tartan.map((el, index) => {           return (             <rect               fill={el.fill}               width={el.size}               height="100%"               x={cumulativeSizes[index - 1] || 0}               y="0"             />           )         })}       </g>     </svg>   ) }

Using a tartan SVG tile as a background image

On tartanify.com, each individual tartan is used as a background image on a full-screen element. This requires some extra manipulation since we don’t have our tartan pattern tile as an SVG image. We’re also unable to use an inline SVG directly in the background-image property.

Fortunately, encoding the SVG as a background image does work:

.bg-element {   background-image: url('data:image/svg+xml;charset=utf-8,<svg>...</svg>'); }

Let’s now create an SvgBg component. It takes the tartan array as props and returns a full-screen div with the tartan pattern as background.

We need to convert the SvgTile React object into a string. The ReactDOMServer object allows us to render components to static markup. Its method renderToStaticMarkup is available both in the browser and on the Node server. The latter is important since later we will server render the tartan pages with Gatsby.

const tartanStr = ReactDOMServer.renderToStaticMarkup(<SvgTile tartan={tartan} />)

Our SVG string contains hex color codes starting with the # symbol. At the same time, # starts a fragment identifier in a URL. It means our code will break unless we escape all of those instances. That’s where the built-in JavaScript encodeURIComponent function comes in handy.

const SvgBg = ({ tartan }) => {   const tartanStr = ReactDOMServer.renderToStaticMarkup(<SvgTile tartan={tartan} />)   const tartanData = encodeURIComponent(tartanStr)   return (     <div       style={{         width: "100%",         height: "100vh",         backgroundImage: `url("data:image/svg+xml;utf8,$ {tartanData}")`,       }}     />   ) }

Making an SVG tartan tile downloadable

Let’s now download our SVG image.

The SvgDownloadLink component takes svgData (the already encoded SVG string) and fileName as props and creates an anchor (<a>) element. The download attribute prompts the user to save the linked URL instead of navigating to it. When used with a value, it suggests the name of the destination file.

const SvgDownloadLink = ({ svgData, fileName = "file" }) => {   return (     <a       download={`$ {fileName}.svg`}       href={`data:image/svg+xml;utf8,$ {svgData}`}     >       Download as SVG     </a>   ) }

Converting an SVG tartan tile to a high-res PNG image file

What about users that prefer the PNG image format over SVG? Can we provide them with high resolution PNGs?

The PngDownloadLink component, just like SvgDownloadLink, creates an anchor tag and has the tartanData and fileName as props. In this case however, we also need to provide the tartan tile size since we need to set the canvas dimensions.

const Tile = SvgTile({tartan}) // Tartan tiles are always square const tartanSize = Tile.props.width

In the browser, once the component is ready, we draw the SVG tile on a <canvas> element. We’ll use the canvas toDataUrl() method that returns the image as a data URI. Finally, we set the date URI as the href attribute of our anchor tag.

Notice that we use double dimensions for the canvas and double scale the ctx. This way, we will output a PNG that’s double the size, which is great for high-resolution usage.

const PngDownloadLink = ({ svgData, width, height, fileName = "file" }) => {   const aEl = React.createRef()   React.useEffect(() => {     const canvas = document.createElement("canvas")     canvas.width = 2 * width     canvas.height = 2 * height     const ctx = canvas.getContext("2d")     ctx.scale(2, 2)     let img = new Image()     img.src = `data:image/svg+xml, $ {svgData}`     img.onload = () => {       ctx.drawImage(img, 0, 0)       const href = canvas.toDataURL("image/png")       aEl.current.setAttribute("href", href)     }   }, [])   return (     <a        ref={aEl}        download={`$ {fileName}.png`}     >       Download as PNG     </a>   ) }

For that demo, I could have skipped React’s useEffect hook and the code would worked fine. Nevertheless, our code is executed both on the server and in the browser, thanks to Gatsby. Before we start creating the canvas, we need to be sure that we are in a browser. We should also make sure the anchor element is ”ready” before we modify its attribute. 

Making a static website out of CSV with Gatsby

If you haven’t already heard of Gatsby, it’s a free and open source framework that allows you to pull data from almost anywhere and generate static websites that are powered by React.

Tartanify.com is a Gatsby website coded by myself and designed by Sylvain. At the beginning of the project, all we had was a huge CSV file (seriously, 5,495 rows), a method to convert the palette and threadcount strings into the tartan SVG structure, and an objective to give Gatsby a try.

In order to use a CSV file as the data source, we need two Gatsby plugins: gatsby-transformer-csv and gatsby-source-filesystem. Under the hood, the source plugin reads the files in the /src/data folder (which is where we put the tartans.csv file), then the transformer plugin parses the CSV file into JSON arrays.

// gatsby-config.js module.exports = {   /* ... */   plugins: [     'gatsby-transformer-csv',     {       resolve: 'gatsby-source-filesystem',       options: {         path: `$ {__dirname}/src/data`,         name: 'data',       },     },   ], }

Now, let’s see what happens in the gatsby-node.js file. The file is run during the site-building process. That’s where we can use two Gatsby Node APIs: createPages and onCreateNode. onCreateNode is called when a new node is created. We will add two additional fields to a tartan node: its unique slug and a unique name. It is necessary since the CSV file contains a number of tartan variants that are stored under the same name.

// gatsby-node.js // We add slugs here and use this array to check if a slug is already in use let slugs = [] // Then, if needed, we append a number let i = 1  exports.onCreateNode = ({ node, actions }) => {   if (node.internal.type === 'TartansCsv') {     // This transforms any string into slug     let slug = slugify(node.Name)     let uniqueName = node.Name     // If the slug is already in use, we will attach a number to it and the uniqueName     if (slugs.indexOf(slug) !== -1) {       slug += `-$ {i}`       uniqueName += ` $ {i}`       i++     } else {       i = 1     }     slugs.push(slug)        // Adding fields to the node happen here     actions.createNodeField({       name: 'slug',       node,       value: slug,     })     actions.createNodeField({       name: 'Unique_Name',       node,       value: uniqueName,     })   } }

Next, we create pages for each individual tartan. We want to have access to its siblings so that we can navigate easily. We will query the previous and next edges and add the result to the tartan page context.

// gatsby-node.js exports.createPages = async ({ graphql, actions }) => {   const { createPage } = actions   const allTartans = await graphql(`     query {       allTartansCsv {         edges {           node {             id             fields {               slug             }           }           previous {             fields {               slug               Unique_Name             }           }           next {             fields {               slug               Unique_Name             }           }         }       }     }   `)   if (allTartans.errors) {     throw allTartans.errors   }   allTartans.data.allTartansCsv.edges.forEach(     ({ node, next, previous }) => {       createPage({         path: `/tartan/$ {node.fields.slug}`,         component: path.resolve(`./src/templates/tartan.js`),         context: {           id: node.id,           previous,           next,         },       })     }   ) }

We decided to index tartans by letters and create paginated letter pages. These pages list tartans with links to their individual pages. We display a maximum of 60 tartans per page, and the number of pages per letter varies. For example, the letter “a” will have have four pages: tartans/a, tartans/a/2, tartans/a/3 and tartans/a/4. The highest number of pages (15) belongs to “m” due to a high number of traditional names starting with “Mac.”

The tartans/a/4 page should point to tartans/b as its next page and tartans/b should point to tartans/a/4 as its previous page.

We will run a for of loop through the letters array ["a", "b", ... , "z"] and query all tartans that start with a given letter. This can be done with filter and regex operator:

allTartansCsv(filter: { Name: { regex: "/^$ {letter}/i" } })

The previousLetterLastIndex variable will be updated at the end of each loop and store the number of pages per letter. The /tartans/b page need to know the number of a pages (4) since its previous link should be tartans/a/4.

// gatsby-node.js const letters = "abcdefghijklmnopqrstuvwxyz".split("") exports.createPages = async ({ graphql, actions }) => {   const { createPage } = actions   // etc.    let previousLetterLastIndex = 1   for (const letter of letters) {     const allTartansByLetter = await graphql(`       query {         allTartansCsv(filter: {Name: {regex: "/^$ {letter}/i"}}) {           nodes {             Palette             fields {               slug               Unique_Name             }           }           totalCount         }       }     `)     if (allTartansByLetter.errors) {       throw allTartansByLetter.errors     }     const nodes = allTartansByLetter.data.allTartansCsv.nodes     const totalCountByLetter = allTartansByLetter.data.allTartansCsv.totalCount     const paginatedNodes = paginateNodes(nodes, pageLength)     paginatedNodes.forEach((group, index, groups) => {       createPage({         path:           index > 0 ? `/tartans/$ {letter}/$ {index + 1}` : `/tartans/$ {letter}`,         component: path.resolve(`./src/templates/tartans.js`),         context: {           group,           index,           last: index === groups.length - 1,           pageCount: groups.length,           letter,           previousLetterLastIndex,         },       })     })     previousLetterLastIndex = Math.ceil(totalCountByLetter / pageLength)   } }

The paginateNode function returns an array where initial elements are grouped by pageLength

const paginateNodes = (array, pageLength) => {   const result = Array()   for (let i = 0; i < Math.ceil(array.length / pageLength); i++) {     result.push(array.slice(i * pageLength, (i + 1) * pageLength))   }   return result }

Now let’s look into the tartan template. Since Gatsby is a React application, we can use the components that we were building in the first part of this article.

// ./src/templates/tartan.js import React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" import SvgTile from "../components/svgtile" import SvgBg from "../components/svgbg" import svgAsString from "../components/svgasstring" import SvgDownloadLink from "../components/svgdownloadlink" import PngDownloadLink from "../components/pngdownloadlink"  export const query = graphql`   query($ id: String!) {     tartansCsv(id: { eq: $ id }) {       Palette       Threadcount       Origin_URL       fields {         slug         Unique_Name       }     }   } ` const TartanTemplate = props => {   const { fields, Palette, Threadcount } = props.data.tartansCsv   const {slug} = fields   const svg = SvgTile({     palette: Palette,     threadcount: Threadcount,   })   const svgData = svgAsString(svg)   const svgSize = svg.props.width      return (     <Layout>       <SvgBg svg={svg} />       {/* title and navigation component comes here */}       <div className="downloads">         <SvgDownloadLink svgData={svgData} fileName={slug} />         <PngDownloadLink svgData={svgData} size={svgSize} fileName={slug} />       </div>     </Layout>   ) } export default TartanTemplate

Finally let’s focus on the tartans index pages (the letter pages).

// ./src/templates/tartans.js import React from "react" import Layout from "../components/layout" import {Link} from "gatsby" import TartansNavigation from "../components/tartansnavigation" const TartansTemplate = ({ pageContext }) => {   const {     group,     index,     last,     pageCount,     letter,     previousLetterLastIndex,   } = pageContext    return (     <Layout>       <header>         <h1>{letter}</h1>       </header>       <ul>         {group.map(node => {           return (             <li key={node.fields.slug}>               <Link to={`/tartan/$ {node.fields.slug}`}>                 <span>{node.fields.Unique_Name}</span>               </Link>             </li>           )         })}       </ul>       <TartansNavigation         letter={letter}         index={index}         last={last}         previousLetterLastIndex={previousLetterLastIndex}       />     </Layout>   ) } export default TartansTemplate

The TartansNavigation component adds next-previous navigation between the index pages.

// ./src/components/tartansnavigation.js import React from "react" import {Link} from "gatsby"  const letters = "abcdefghijklmnopqrstuvwxyz".split("") const TartansNavigation = ({   className,   letter,   index,   last,   previousLetterLastIndex, }) => {   const first = index === 0   const letterIndex = letters.indexOf(letter)   const previousLetter = letterIndex > 0 ? letters[letterIndex - 1] : ""   const nextLetter =     letterIndex < letters.length - 1 ? letters[letterIndex + 1] : ""      let previousUrl = null, nextUrl = null    // Check if previousUrl exists and create it   if (index === 0 && previousLetter) {     // First page of each new letter except "a"     // If the previous letter had more than one page we need to attach the number      const linkFragment =       previousLetterLastIndex === 1 ? "" : `/$ {previousLetterLastIndex}`     previousUrl = `/tartans/$ {previousLetter}$ {linkFragment}`   } else if (index === 1) {     // The second page for a letter     previousUrl = `/tartans/$ {letter}`   } else if (index > 1) {     // Third and beyond     previousUrl = `/tartans/$ {letter}/$ {index}`   }      // Check if `nextUrl` exists and create it   if (last && nextLetter) {     // Last page of any letter except "z"     nextUrl = `/tartans/$ {nextLetter}`   } else if (!last) {     nextUrl = `/tartans/$ {letter}/$ {(index + 2).toString()}`   }    return (     <nav>       {previousUrl && (         <Link to={previousUrl} aria-label="Go to Previous Page" />       )}       {nextUrl && (         <Link to={nextUrl} aria-label="Go to Next Page" />       )}     </nav>   ) } export default TartansNavigation

Final thoughts

Let’s stop here. I tried to cover all of the key aspects of this project. You can find all the tartanify.com code on GitHub. The structure of this article reflects my personal journey — understanding the specificity of tartans, translating them into SVG, automating the process, generating image versions, and discovering Gatsby to build a user-friendly website. It was maybe not as fun as our Scottish journey itself 😉, but I truly enjoyed it. Once again, a side project proved to be the best way to dig into new technology.

The post How We Created a Static Site That Generates Tartan Patterns in SVG 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]

Table design patterns on the web

Chen Hui Jing has tackled a ton of design patterns for tables that might come in handy when creating tables that are easy to read and responsive for the web:

There are a myriad of table design patterns out there, and which approach you pick depends heavily on the type of data you have and the target audience for that data. At the end of the day, tables are a method for the organisation and presentation of data. It is important to figure out which information matters most to your users and decide on an approach that best serves their needs.

This reminds me of way back when Chris wrote about responsive data tables and just how tricky they are to get right. Also there’s a great post by Richard Rutter in a similar vein where he writes about the legibility of tables and fine typography:

Many tables, such as financial statements or timetables, are made up mostly of numbers. Generally speaking, their purpose is to provide the reader with numeric data, presented in either columns or rows, and sometimes in a matrix of the two. Your reader may use the table by scanning down the columns, either searching for a data point or by making comparisons between numbers. Your reader may also make sense of the data by simply glancing at the column or row. It is far easier to compare numbers if the ones, tens and hundreds are all lined up vertically; that is, all the digits should occupy exactly the same width.

One of my favorite table patterns that I now use consistently is one with a sticky header. Like this demo here:

See the Pen
Table Sticky Header
by Robin Rendle (@robinrendle)
on CodePen.

As a user myself, I find that when I’m scrolling through large tables of data with complex information, I tend to forget what one column is all about and then I’ll have to scroll all the way back up to the top again to read the column header.

Anyway, all this makes me think that I would read a whole dang book on the subject of the <table> element and how to design data accurately and responsively.

Direct Link to ArticlePermalink

The post Table design patterns on the web appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]