Developer News

Using CSS Cascade Layers to Manage Custom Styles in a Tailwind Project

Css Tricks - Wed, 08/24/2022 - 3:11am

If a utility class only does one thing, chances are you don’t want it to be overridden by any styles coming from elsewhere. One approach is to use !important to be 100% certain the style will be applied, regardless of specificity conflicts.

The Tailwind config file has an !important option that will automatically add !important to every utility class. There’s nothing wrong with using !important this way, but nowadays there are better ways to handle specificity. Using CSS Cascade Layers we can avoid the heavy-handed approach of using !important.

Cascade layers allow us to group styles into “layers”. The precedence of a layer always beats the specificity of a selector. Specificity only matters inside each layer. Establishing a sensible layer order helps avoid styling conflicts and specificity wars. That’s what makes CSS Cascade Layers a great tool for managing custom styles alongside styles from third-party frameworks, like Tailwind.

A Tailwind source .css file usually starts something like this:

@tailwind base; @tailwind components; @tailwind utilities; @tailwind variants;

Let’s take a look at the official Tailwind docs about directives:

Directives are custom Tailwind-specific at-rules you can use in your CSS that offer special functionality for Tailwind CSS projects. Use the @tailwind directive to insert Tailwind’s base, components, utilities and variants styles into your CSS.

In the output CSS file that gets built, Tailwind’s CSS reset — known as Preflight — is included first as part of the base styles. The rest of base consists of CSS variables needed for Tailwind to work. components is a place for you to add your own custom classes. Any utility classes you’ve used in your markup will appear next. Variants are styles for things like hover and focus states and responsive styles, which will appear last in the generated CSS file.

The Tailwind @layer directive

Confusingly, Tailwind has its own @layer syntax. This article is about the CSS standard, but let’s take a quick look at the Tailwind version (which gets compiled away and doesn’t end up in the output CSS). The Tailwind @layer directive is a way to inject your own extra styles into a specified part of the output CSS file.

For example, to append your own styles to the base styles, you would do the following:

@layer base { h1 { font-size: 30px; } }

The components layer is empty by default — it’s just a place to put your own classes. If you were doing things the Tailwind way, you’d probably use @apply (although the creator of Tailwind recently advised against it), but you can also write classes the regular way:

@layer components { .btn-blue { background-color: blue; color: white; } }

The CSS standard is much more powerful. Let’s get back to that…

Using the CSS standard @layer

Here’s how we can rewrite this to use the CSS standard @layer:

@layer tailwind-base, my-custom-styles, tailwind-utilities; @layer tailwind-base { @tailwind base; } @layer tailwind-utilities { @tailwind utilities; @tailwind variants; }

Unlike the Tailwind directive, these don’t get compiled away. They’re understood by the browser. In fact, DevTools in Edge, Chrome, Safari, and Firefox will even show you any layers you’ve defined.

You can have as many layers as you want — and name them whatever you want — but in this example, all my custom styles are in a single layer (my-custom-styles). The first line establishes the layer order:

@layer tailwind-base, my-custom-styles, tailwind-utilities;

This needs to be provided upfront. Be sure to include this line before any other code that uses @layer. The first layer in the list will be the least powerful, and the last layer in the list will be the most powerful. That means tailwind-base is the least powerful layer and any code in it will be overridden by all the subsequent layers. That also means tailwind-utilities will always trump any other styles — regardless of source order or specificity. (Utilities and variants could go in separate layers, but the maintainers of Tailwind will ensure variants always trump utilities, so long as you include the variants below the utilities directive.)

Anything that isn’t in a layer will override anything that is in a layer (with the one exception being styles that use !important). So, you could also opt to leave utilities and variants outside of any layer:

@layer tailwind-base, tailwind-components, my-custom-styles; @layer tailwind-base { @tailwind base; } @layer tailwind-components { @tailwind components; } @tailwind utilities; @tailwind variants;

What did this actually buy us? There are plenty of times when advanced CSS selectors come in pretty handy. Let’s create a version of :focus-within that only responds to keyboard focus rather than mouse clicks using the :has selector (which lands in Chrome 105). This will style a parent element when any of its children receive focus. Tailwind 3.1 introduced custom variants — e.g. <div class="[&:has(:focus-visible)]:outline-red-600"> — but sometimes it’s easier to just write CSS:

@layer tailwind-base, my-custom-styles; @layer tailwind-base { @tailwind base; } @tailwind utilities; @layer my-custom-styles { .radio-container { padding: 4px 24px; border: solid 2px rgb(230, 230, 230); } .radio-container:has(:focus-visible) { outline: solid 2px blue; } }

Let’s say in just one instance we want to override the outline-color from blue to something else. Let’s say the element we’re working with has both the Tailwind class .outline-red-600 and our own .radio-container:has(:focus-visible) class:

<div class="outline-red-600 radio-container"> ... </div>

Which outline-color will win?

Ordinarily, the higher specificity of .radio-container:has(:focus-visible) would mean the Tailwind class has no effect — even if it’s lower in the source order. But, unlike the Tailwind @layer directive that relies on source order, the CSS standard @layer overrules specificity.

As a result, we can use complex selectors in our own custom styles but still override them with Tailwind’s utility classes when we need to — without having to resort to heavy-handed !important usage to get what we want.

Using CSS Cascade Layers to Manage Custom Styles in a Tailwind Project originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Removing jQuery from GOV.UK

Css Tricks - Tue, 08/23/2022 - 3:04am

The GOV.UK team recently published “How and why we removed jQuery from GOV.UK“. This was an insightful look at how an organization can assess its tooling and whether something is still the best tool for the job. This is not a nudge to strip libraries out of your current project right now! Many of us may still be supporting legacy projects and browser requirements that prevent this from being a viable option.

Some of the criticism appears to be that the library size argument is negligible on modern network speeds and caching.

GOV.UK posted an update to address this criticism with metrics – “The impact of removing jQuery on our web performance“.

This article also makes the case for improving maintenance. Instead of upgrading disparate outdated versions of code and having to address security updates in a piecemeal approach, removing the dependency reduces this footprint. This is the dream of having the luxury for addressing technical debt.

Previously, GitHub also documented how they incrementally decoupled jQuery from their front-end code. Improving maintenance and developer experience played a role into their decision.

What caught my eye in particular was the link to the documentation on how to remove jQuery. Understanding how to decouple and perform migration steps are maintenance tasks that will continue to come up for websites and it’s reassuring to have a guide from someone that had to do the same.

Further musing on this subject turned up the old chestnuts “You Might Not Need jQuery” (2014), “(Now More Than Ever) You Might Not Need jQuery” (2017), “Is jQuery still relevant? (1)” (2016), and “Is jQuery still relevant? (2)” (2017).

To Shared LinkPermalink on CSS-Tricks

Removing jQuery from GOV.UK originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

When Do You Use CSS Columns?

Css Tricks - Thu, 08/18/2022 - 3:24am

That ain’t rhetorical: I’m really interested in finding great use cases for CSS multi-column layouts.

The answer seems straightforward. Use columns when you want to split any content into columns, right? Here is generally the sort of example you’ll find in articles that show how CSS mutli-column layouts work, including our very own Almanac:

CodePen Embed Fallback

Right on. But is this an actual use case? Mmmmmaybe. If the text is relatively brief, then perhaps it’s a nice touch. That’s how I sold it to myself when redesigning my website a few years ago. It’s not that way today, but this is what it looked like then:

But an entire long-form article split into columns? I love it in newspapers but am hesitant to scroll down a webpage to read one column, only to scroll back up to do it again.

I suppose we can use it to place two elements side-by-side, but flexbox is way more suited for that. Plus, a limitation prevents us from selecting the columns to size them individually. The columns have to be the same width.

One thing columns have going for them is that they are the only CSS layout method that fragments content. (That is, unless we’re counting CSS Regions… what happened to those, anyway?!) So, if you wanna split a paragraph up into columns, it’s already possible without additional wrappers.

When else might you need to split a continuous block of content into columns? I remember needing to do that when I had a big ol’ unordered list of items. I like the way lists can make content easy to scan, but long lists can make one side of the page look super heavy. Let’s say, for example, that we were listing out all the post tags for CSS-Tricks in alphabetical groups. A multi-column layout works beautifully for that:

CodePen Embed Fallback

Go ahead and try resizing the viewport width. Three columns are defined but the number will change based on the amount of available space. Gotta love all that responsive goodness without the media query work!

I was working on a demo for the :left pseudo-class and reached for columns because it’s a great way to fragment things for printing demos. So, I guess there’s another use case. And while making a demo, I realized that a multi-column layout could be used to create a masonry grid of items, like an image gallery:

CodePen Embed Fallback

But what else? Are we limited to short paragraphs, long lists, and free-flowing grids?

When Do You Use CSS Columns? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Why (and How) I Write Code With Pencil and Paper

Css Tricks - Wed, 08/17/2022 - 3:21am

If the thought of handwriting code seems silly, it might surprise you to know that it’s inevitable. If you’re unsure, think about the last job interview you did, and remember how there was no computer around in the interview room — just your interviewers, a blank sheet of paper, and a blue ball-point pen.

For the students among you, it’s even a bigger deal as your grades hang in by the lines of code you had strategically squeezed into the available space in your answer sheet.

And not just that, experienced programmers can point you to the bundle of A4 sheets they had removed from the office copy machine to scribble down a particularly complex algorithm they had been working on.

So whether you’re an exam student, potential job interviewee, or someone wanting to resolve their programming dead ends, I hope this article helps you out when you put your pen to the paper to code.

Although I will focus on the analog aspect of writing code, you can apply these steps to coding in any form or language. So consider this to be also like a generic coding guideline that works specifically for me but can also be very useful to you in your work.

Why write it down?

Before we start, it’s essential to understand that no one expects you to jot down production-ready code in a notebook. It’s not like you can drop that into a code editor and compile it without an error. If producing perfect code was the goal, you would be seated in front of a computer in the interview rooms and exam halls.

The purpose of handwriting code is to work through logic in advance. There’s s desire to “get in the browser” as soon as possible in design, but there is conventional wisdom in sketching designs by hand. A low-fidelity medium encourages quick experimentation and inexpensive mistakes.

The toil of trying to figure out how to affect surrounding items with one click (from my last article)

The same can be true of code, mainly when working out syntax and semantics. That said, getting the correct syntax and semantics is always a plus point, though not the sole focus of the whole handwriting exercise.

Let’s see where we can start when it comes to handwriting code.

Know your question

During my final year in college, I couldn’t do an internship or even attend campus interviews because of health reasons. As a result, my very first job interview was quite literal with high stakes.

When I look back now, the interview was pretty easy. But having never attended one before, I was anxious beyond reason. The first thing the interviewers asked about programming was if I could output an inverted triangle made of asterisks. As I said, it was easy — nothing a for loop can’t handle, right? But like I said, my anxiety was through the roof as well.

I took a deep breath, pressed my palm against the blank sheet of paper they had laid out for me, slid it as slow as possible towards me on the table (buying time, of course), clicked the pen, and then I did something right.

I first drew an inverted triangle made of asterisks. That’s how I found my feet on the ground to start answering their question.

I’ve seen otherwise brilliant developers get something wrong simply because they never fully grasp what it is they are solving.

The questions we work with are not like the questions physicists or mathematicians solve. They get a set of parameters and find the missing ones; our questions are also our results. We are already told what our results are — we have to figure out how to reach them. That’s why it’s imperative to know the question well because you’ll see the result.

Writing down or drawing out what you want to output is one of the best ways to start your coding. I understand that in our fast-paced industry, the expectation is that we have to jump right into the programming by running a “hello world” demo. And that’s great to familiarize yourself with an unfamiliar syntax and shake off your anxiousness about trying something new.

But when someone asks you a question and gives you a result to work up to, wouldn’t it just be better to put that down first? That question/result is not only your starting point but also your point of reference. At any step in your coding, you can look at it to ensure you’re working towards it and that you’re on the right track.

So whether in your answer sheets or in that blank A4 paper you’re about to write in, start by taking a second and writing down what it is you’re trying to output. You can put it in the margins or a corner if you don’t want it to be a part of your answer. Just make sure it’s somewhere where you can keep referencing it.

Outline your code

This step is like a double-edged sword. It can get you a roadmap to your program or waste your time. My job is to make sure it’s the former.

So, first and foremost, I like to say: outlining code is unnecessary if the scope of your problem or question is small. Again, this practice is neither prescriptive nor universal to all projects or situations. Imagine I’m your interviewer, and I ask you to write how to center an element in a web page using CSS in as many ways as possible. You won’t exactly be needing an outline for this. The code snippets are relatively small for each method.

But now, let’s say I assign you to write a web application that captures user signatures via a touchscreen interface and then saves the signature on the server. Not so straightforward, right? You’ve more than one thing to figure out. Perhaps, a little outline can help.

  1. UI for capturing signature — HTML Canvas? WebGL?
  2. Disable pointer events on the rest of the web page when the user is signing
  3. Convert and save the captured image to a PNG file — JS
  4. Then convert it to blob (maybe) and save it to the visitor’s log data table.

I’ve written a rough sequence of actions I think I might have to code. It could’ve been shorter or longer, depending on what I wanted from it.

I highly recommend outlining code for client projects. Write the outline along with your user requirements or on the back of wireframes you’ve printed out.

Your quick snapshot of bullet points gives you a map, a to-do list, and a checklist to verify against when you reach the end of the project — pretty much your whole project’s summary in a low-fidelity list. It can also become a template to start your next similar project.

But like I said before, this step is like a double-edged sword. You’ll have to keep this short for examinees and interviewees when there are time constraints.

If you don’t know where to start, write down just three essential functions you’ll have to code in your application, and if you have got the time, make it five.

But that’s about it. Spend as little time as possible on this, and don’t sweat over the details. The outline is not going to score you extra points. It’s there only to help you make sure you have everything covered. It captures your initial gut reaction and keeps you honest throughout the project’s life.

Longhand vs. shorthand A quick reference to disable text selection

Time to start coding. So, what do you write? “Bdrs” or “border-radius“; “div -> p” or “<div><p></div></p>“; “pl()” or “println()“; “q()” or “querySelector()“?

If someone else is grading your code, then there’s no choice. Leave out abbreviations, pseudo-codes, Emmet shortcuts, and any other form of shorthand writing. Otherwise, there’s no reason to assume that anyone reading this knows what your abbreviations mean.

It’s really up to you.

If you’ve gotten out of touch with writing by hand — and many of us have — it’s better not to go overboard with the longhand notations, as they get tedious. At the same time, there’s no such thing as being too frugal with your writing. Not if you want to be able to look back on it one day and understand what you’d written down.

I have an open file in my note-taking app and a lined notepad on my desk where I write down code snippets I want to save for later reference. They are unorganized, just a long stream of snippets. That’s why when I browse through older notes, I wouldn’t know what I meant to write if I had not written them down clearly.

I forget syntaxes all the time. For instance, I’ve been using the arrow notation for JavaScript functions since it was introduced (because it’s shorter), and I’m pretty sure if someone suddenly asks me to define a function using the function keyword, I might even misplace the parentheses or the function name, inciting a syntax error.

It’s not unusual for us to forget syntaxes we haven’t used in a while. That’s why it’s better to write your notes clearly when you know you need them for future reference.

The non-sequential flow of code

Unlike the last step, which doesn’t apply to those of you interviewees and test-takers, this one is catered especially to you.

Most programming languages are interpreted, compiled, and executed so that sometimes pre-written code in the source is executed later when called. We do it in JavaScript, for example, with function calling — functions can be defined initially, then executed later. Examinees and interviewees can use this to start working on the critical point of your answer first.

As I’ve said from the very beginning, the purpose of handwriting code is to work through or test the logic of whatever it is you program. It’s best when you focus on resolving that first.

Let’s take a classic textbook example — a program to find the nth Fibonacci number. If I were to write a simple outline for it, it would be something like this:

  1. Get the input.
  2. Calculate the Fibonacci number.
  3. Summarise the output.
  4. Print the output.

All the steps in that outline are essential; however, 1, 3, and 4 are more obligatory. They are necessary but not important enough to focus on right away.

It’s better to start writing down the code to calculate the Fibonacci number rather than to fetch the input. Wrap it in a function, then go ahead and write the code sequentially and write down a line to call that function where appropriate.

Spend your time writing code that focuses on the heart of the problem.

Real professionals can skip ahead. Let’s say I have a client project, and I have to work with some triangle geometry — got two sides, opposite angle, and gotta find the third side’s length. And I’ve decided to scribble on paper to get started rather than opening my IDE.

First, I would draw the triangle, of course (that’s something I’m very experienced with, as you can tell). I would write down some sample lengths and angles. Then I’d write the formula (compliments of online searching, for sure), and then I’d jump right to the code for the function.

There’s no point in me writing down the obligatory steps even though I’ll need them in production-ready code. But it would be different if I had to write that on an answer sheet in an exam. I can’t skip the other steps; however, I can still start with the code for the formula.

Pseudo-code

Chris has already written a handy article on pseudo-code that I highly recommend you give a solid read.

For all those professionals who feel like the whole handwriting code thing doesn’t seem like your cup of tea but still might be curious if it can help you, then pseudo-code might be the balance you’re looking for.

It’s similar to outlining the code, as I mentioned in one of the previous steps. However, it’s briefer and feels more like shorthand coding. It’s sometimes also referred to as “skeleton code.”

Here’s some quick pseudo-code for a CSS grid layout:

Grid 5 60px rows 6 100px columns

There isn’t much to write! So, even though putting a pencil to paper is excellent for this sort of thing, it’s just as effective, fast, and inexpensive to jot some pseudo code into whatever program you’re using.

Space and comments

I believe code is 90% keywords and 10% tabs. Withoutspacesthereadabilityofwordsdecreases. Indentations are necessary for handwritten code as well. However, please don’t use it for every level because the width of the paper will limit you. Use spaces judiciously, but use them.

Prized OG snippet, written with extra TLC

If you’re writing code for your use, I also believe that if you’ve followed everything I’ve mentioned so far and have already written down your output and an outline on the page, you may not even need to include comments. Comments tell you quickly what its following set of code does. If you have already written and read an outline for the code, then comments are redundant notes.

However, if your judgment says to put down one, then do it. Add it to the right side of the code (since you won’t be able to insert it between already written lines the way you could in, say, VS Code). Use forward slashes, brackets, or arrows to denote that they are comments.

For examinees who are unconfident with a certain syntax, write down comments. This way, at least, you’re letting the person grading your paper know your intention with that incorrectly formatted code. And use only the correct delimiters to denote comments — for example, that would be the forward slashes for JavaScript.

Analog vs. digital

As I mentioned earlier, everything I’m providing here can is generic coding advice. If you don’t want to try this with physical paper, any note-taking application also works.

But if you’re going to try the digital route, my recommendation is to try using something other than a straight note-taking app. Work with more visual digital tools — flow diagrams, mind maps, wireframes, etc. They can help you visualize your result, the outlines, and the code itself.

I am not much of a digital citizen (except for working on the web and recently converting to reading e-books), so I stick to physical notebooks.

My favorite tools for handwriting code

Any pencil and paper will do! But there are lots of options out there, and these are a few choice tools I use:

There is no “write” way to code

I hope, if nothing else, my little way of handwriting code with pencil and paper makes you evaluate the way you already plan and write code. I like knowing how other developers approach their work, and this is my way of giving you a peek into the way I do things.

Again, nothing here is scientific or an exact art. But if you want to give handwritten code planning a try, here’s everything we’ve covered in a nice ordered list:

  1. Start by writing down (with sample data, if needed) the output of your code.
  2. Write an outline for the code. Please keep it to three steps for small projects or ones that are less complex.
  3. Use longhand notations. Developers writing for themselves can use shorthand notations as long as the writing is legible and makes sense to you when you refer to it later.
  4. When under a time constraint, consider writing the code that tackles the heart of the problem first. Later, write down a call to that code at the right place in your sequential code.
  5. If you feel confident, try writing pseudo code addressing the main idea.
  6. Use proper indentations and spaces — and be mindful of the paper’s width.

That’s it! When you’re ready to try writing code by hand, I hope this article makes it easy for you to start. And if you’re sitting down for an exam or an interview, I hope this helps you focus on getting the questions right.

Why (and How) I Write Code With Pencil and Paper originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

CSS Grid and Custom Shapes, Part 1

Css Tricks - Mon, 08/15/2022 - 3:13am

In a previous article, I looked at CSS Grid’s ability to create complex layouts using its auto-placement powers. I took that one step further in another article that added a zooming hover effect to images in a grid layout. This time, I want to dive into another type of grid, one that works with shapes.

Like, what if the images aren’t perfectly square but instead are shaped like hexagons or rhombuses? Spoiler alert: we can do it. In fact, we’re going to combine CSS Grid techniques we’ve looked at and drop in some CSS clip-path and mask magic to create fancy grids of images for just about any shape you can imagine!

Let’s start with some markup

Most of the layouts we are going to look at may look easy to achieve at first glance, but the challenging part is to achieve them with the same HTML markup. We can use a lot of wrappers, divs, and whatnot, but the goal of this post is to use the same and smallest amount of HTML code and still get all the different grids we want. After all, what’s CSS but a way to separate styling and markup? Our styling should not depend on the markup, and vice versa.

This said, let’s start with this:

<div class="gallery"> <img src="..." alt="..."> <img src="..." alt="..."> <img src="..." alt="..."> <img src="..." alt="..."> <!-- as many times as we want --> </div>

A container with images is all that we need here. Nothing more!

CSS Grid of Hexagons

This is also sometimes referred to as a “honeycomb” grid.

CodePen Embed Fallback

There are already plenty of other blog posts out there that show how to make this. Heck, I wrote one here on CSS-Tricks! That article is still good and goes way deep on making a responsive layout. But for this specific case, we are going to rely on a much simpler CSS approach.

First, let’s use clip-path on the images to create the hexagon shape and we place all of them in the same grid area so they overlap.

.gallery { --s: 150px; /* controls the size */ display: grid; } .gallery > img { grid-area: 1/1; width: var(--s); aspect-ratio: 1.15; object-fit: cover; clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%); } clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%)

Nothing fancy yet. All the images are hexagons and above each other. So it looks like all we have is a single hexagon-shaped image element, but there are really seven.

CodePen Embed Fallback

The next step is to apply a translation to the images to correctly place them on the grid.

Notice that we still want one of the images to remain in the center. The rest are placed around it using CSS translate and good ol’ fashioned geometry. Here’s are the mock formulas I came up with for each image in the grid:

translate((height + gap)*sin(0deg), (height + gap)*cos(0)) translate((height + gap)*sin(60deg), (height + gap)*cos(60deg)) translate((height + gap)*sin(120deg), (height + gap)*cos(120deg)) translate((height + gap)*sin(180deg), (height + gap)*cos(180deg)) translate((height + gap)*sin(240deg), (height + gap)*cos(240deg)) translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))

A few calculations and optimization later (let’s skip that boring part, right?) we get the following CSS:

.gallery { --s: 150px; /* control the size */ --g: 10px; /* control the gap */ display: grid; } .gallery > img { grid-area: 1/1; width: var(--s); aspect-ratio: 1.15; object-fit: cover; clip-path: polygon(25% 0%, 75% 0%, 100% 50% ,75% 100%, 25% 100%, 0 50%); transform: translate(var(--_x,0), var(--_y,0)); } .gallery > img:nth-child(1) { --_y: calc(-100% - var(--g)); } .gallery > img:nth-child(7) { --_y: calc( 100% + var(--g)); } .gallery > img:nth-child(3), .gallery > img:nth-child(5) { --_x: calc(-75% - .87*var(--g)); } .gallery > img:nth-child(4), .gallery > img:nth-child(6) { --_x: calc( 75% + .87*var(--g)); } .gallery > img:nth-child(3), .gallery > img:nth-child(4) { --_y: calc(-50% - .5*var(--g)); } .gallery > img:nth-child(5), .gallery > img:nth-child(6) { --_y: calc( 50% + .5*var(--g)); }

Maybe that’ll be easier when we get real trigonometry functions in CSS!

Each image is translated by the --_x and --_y variables that are based on those formulas. Only the second image (nth-child(2)) is undefined in any selector because it’s the one in the center. It can be any image if you decide to use a different order. Here’s the order I’m using:

With only a few lines of code, we get a cool grid of images. To this, I added a little hover effect to the images to make things fancier.

Guess what? We can get another hexagon grid by simply updating a few values.

CodePen Embed Fallback

If you check the code and compare it with the previous one you will notice that I have simply swapped the values inside clip-path and I switched between --x and --y. That’s all!

CSS Grid of Rhombuses

Rhombus is such a fancy word for a square that’s rotated 45 degrees.

CodePen Embed Fallback

Same HTML, remember? We first start by defining a 2×2 grid of images in CSS:

.gallery { --s: 150px; /* controls the size */ display: grid; gap: 10px; grid: auto-flow var(--s) / repeat(2, var(--s)); place-items: center; } .gallery > img { width: 100%; aspect-ratio: 1; object-fit: cover; }

The first thing that might catch your eye is the grid property. It’s pretty uncommonly used but is super helpful in that it’s a shorthand that lets you define a complete grid in one declaration. It’s not the most intuitive — and not to mention readable — property, but we are here to learn and discover new things, so let’s use it rather than writing out all of the individual grid properties.

grid: auto-flow var(--s) / repeat(2,var(--s)); /* is equivalent to this: */ grid-template-columns: repeat(2, var(--s)); grid-auto-rows: var(--s);

This defines two columns equal to the --s variable and sets the height of all the rows to --s as well. Since we have four images, we will automatically get a 2×2 grid.

Here’s another way we could have written it:

grid-template-columns: repeat(2, var(--s)); grid-template-rows: repeat(2, var(--s));

…which can be reduced with the grid shorthand:

grid: repeat(2,var(--s)) / repeat(2,var(--s));

After setting the grid, we rotate it and the images with CSS transforms and we get this:

CodePen Embed Fallback

Note how I rotate them both by 45deg, but in the opposite direction.

.gallery { /* etc. */ transform: rotate(45deg); } .gallery > img { /* etc. */ transform: rotate(-45deg); }

Rotating the images in the negative direction prevents them from getting rotated with the grid so they stay straight. Now, we apply a clip-path to clip a rhombus shape out of them.

clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%) CodePen Embed Fallback

We are almost done! We need to rectify the size of the image to make them fit together. Otherwise, they’re spaced far apart to the point where it doesn’t look like a grid of images.

The image is within the boundary of the green circle, which is the inscribed circle of the grid area where the image is placed. What we want is to make the image bigger to fit inside the red circle, which is the circumscribed circle of the grid area.

Don’t worry, I won’t introduce any more boring geometry. All you need to know is that the relationship between the radius of each circle is the square root of 2 (sqrt(2)). This is the value we need to increase the size of our images to fill the area. We will use 100%*sqrt(2) = 141% and be done!

.gallery { --s: 150px; /* control the size */ display: grid; grid: auto-flow var(--s) / repeat(2,var(--s)); gap: 10px; place-items: center; transform: rotate(45deg); } .gallery > img { width: 141%; /* 100%*sqrt(2) = 141% */ aspect-ratio: 1; object-fit: cover; transform: rotate(-45deg); clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); }

Like the hexagon grid, we can make things fancier with that nice zooming hover effect:

CodePen Embed Fallback CSS Grid of Triangular Shapes CodePen Embed Fallback

You probably know by now that the big trick is figuring out the clip-path to get the shapes we want. For this grid, each element has its own clip-path value whereas the last two grids worked with a consistent shape. So, this time around, it’s like we’re working with a few different triangular shapes that come together to form a rectangular grid of images.

The three images at the top The three images at the bottom

We place them inside a 3×2 grid with the following CSS:

.gallery { display: grid; gap: 10px; grid-template-columns: auto auto auto; /* 3 columns */ place-items: center; } .gallery > img { width: 200px; /* controls the size */ aspect-ratio: 1; object-fit: cover; } /* the clip-path values */ .gallery > img:nth-child(1) { clip-path: polygon(0 0, 50% 0, 100% 100% ,0 100%); } .gallery > img:nth-child(2) { clip-path: polygon(0 0, 100% 0, 50% 100%); } .gallery > img:nth-child(3) { clip-path: polygon(50% 0, 100% 0, 100% 100%, 0 100%); } .gallery > img:nth-child(4) { clip-path: polygon(0 0, 100% 0, 50% 100%, 0 100%); } .gallery > img:nth-child(5) { clip-path: polygon(50% 0, 100% 100%, 0% 100%); } .gallery > img:nth-child(6) { clip-path: polygon(0 0, 100% 0 ,100% 100%, 50% 100%); } }

Here’s what we get:

CodePen Embed Fallback

The final touch is to make the width of the middle column equal 0 to get rid of the spaces between the images. The same sort of spacing problem we had with the rhombus grid, but with a different approach for the shapes we’re using:

grid-template-columns: auto 0 auto;

I had to fiddle with the clip-path values to make sure they would all appear to fit together nicely like a puzzle. The original images overlap when the middle column has zero width, but after slicing the images, the illusion is perfect:

CSS Pizza Pie Grid

Guess what? We can get another cool grid by simply adding border-radius and overflow to our grid or triangular shapes. &#x1f389;

CodePen Embed Fallback CSS Grid of Puzzle Pieces

This time we are going to play with the CSS mask property to make the images look like pieces of a puzzle.

CodePen Embed Fallback

If you haven’t used mask with CSS gradients, I highly recommend this other article I wrote on the topic because it’ll help with what comes next. Why gradients? Because that’s what we’re using to get the round notches in the puzzle piece shapes.

Setting up the grid should be a cinch by now, so let’s focus instead on the mask part.

CodePen Embed Fallback

As illustrated in the above demo, we need two gradients to create the final shape. One gradient creates a circle (the green part) and the other creates the right curve while filling in the top part.

--g: 6px; /* controls the gap */ --r: 42px; /* control the circular shapes */ background: radial-gradient(var(--r) at left 50% bottom var(--r), green 95%, #0000), radial-gradient(calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%, #0000 95%, red) top/100% calc(100% - var(--r)) no-repeat;

Two variables control the shape. The --g variable is nothing but the grid gap. We need to account for the gap to correctly place our circles so they overlap perfectly when the whole puzzle is assembled. The --r variable controls the size of circular parts of the puzzle shape.

Now we take the same CSS and update a few values in it to create the three other shapes:

CodePen Embed Fallback

We have the shapes, but not the overlapping edges we need to make them fit together. Each image is limited to the grid cell it’s in, so it makes sense why the shapes are sort of jumbled at the moment:

We need to create an overflow by increasing the height/width of the images. From the above figure, we have to increase the height of the first and fourth images while we increase the width of the second and third ones. You have probably already guessed that we need to increase them using the --r variable.

.gallery > img:is(:nth-child(1),:nth-child(4)) { width: 100%; height: calc(100% + var(--r)); } .gallery > img:is(:nth-child(2),:nth-child(3)) { height: 100%; width: calc(100% + var(--r)); }

We are getting closer!

CodePen Embed Fallback

We created the overlap but, by default, our images either overlap on the right (if we increase the width) or the bottom (if we increase the height). But that’s not what we want for the second and fourth images. The fix is to use place-self: end on those two images and our full code becomes this:

CodePen Embed Fallback

Here is another example where I am using a conic gradient instead of a radial gradient. This gives us triangular puzzle pieces while keeping the same underlying HTML and CSS.

CodePen Embed Fallback

A last one! This time I am using clip-path and since it’s a property we can animate, we get a cool hover by simply updating the custom property that controls the shape.

CodePen Embed Fallback Wrapping up

That’s all for this first part! By combining the things we’ve already learned about CSS Grid with some added clip-path and mask magic, we were able to make grid layouts featuring different kinds of shapes. And we used the same HTML markup each time! And the markup itself is nothing more than a container with a handful of image elements!

In the second part, we are going to explore more complex-looking grids with more fancy shapes and hover effects.

I’m planning to take the demo of expanding image panels we made together in this other article:

CodePen Embed Fallback

…and transform it into a zig-zag image panels! And this is only one example among the many we will discover in the next article.

CSS Grid and Custom Shapes, Part 1 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Wed, 12/31/1969 - 2:00pm
Syndicate content
©2003 - Present Akamai Design & Development.