惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
S
Schneier on Security
The Hacker News
The Hacker News
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
I
Intezer
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Schneier on Security
Schneier on Security
Security Latest
Security Latest
AWS News Blog
AWS News Blog
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
有赞技术团队
有赞技术团队
博客园 - 叶小钗
The Last Watchdog
The Last Watchdog
O
OpenAI News
月光博客
月光博客
Hacker News: Ask HN
Hacker News: Ask HN
阮一峰的网络日志
阮一峰的网络日志
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Latest news
Latest news
P
Palo Alto Networks Blog
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
Apple Machine Learning Research
Apple Machine Learning Research
U
Unit 42
PCI Perspectives
PCI Perspectives
博客园 - 聂微东
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
Forbes - Security
Forbes - Security
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
博客园 - 三生石上(FineUI控件)
Application and Cybersecurity Blog
Application and Cybersecurity Blog
罗磊的独立博客
WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security

CSS Articles by Temani Afif

Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks Let’s Play With Gap Decorations! How to Control Infinite CSS Animations (Part 2 of 2) How to Control Infinite CSS Animations (Part 1 of 2) Two Circles, One Arrow, and Anchor Positioning Making a Responsive Pyramidal Grid With Modern CSS | CSS-Tricks How to Create a CSS-only Elastic Text Effect Making Complex CSS Shapes Using shape() | CSS-Tricks Responsive Hexagon Grid Using Modern CSS | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 2) | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 1) | CSS-Tricks Perfectly Pointed Tooltips: To The Corners Perfectly Pointed Tooltips: All Four Sides Perfectly Pointed Tooltips: A Foundation Sequential linear() Animation With N Elements | CSS-Tricks Infinite Marquee Animation using Modern CSS Better CSS Shapes Using shape() — Part 4: Close and Move | CSS-Tricks Drawing CSS Shapes using corner-shape Better CSS Shapes Using shape() — Part 3: Curves | CSS-Tricks Better CSS Shapes Using shape() — Part 2: More on Arcs | CSS-Tricks Better CSS Shapes Using shape() — Part 1: Lines and Arcs | CSS-Tricks Creating Blob Shapes using clip-path: shape() Creating Flower Shapes using clip-path: shape() Custom progress element using the attr() function A CSS-Only Star Rating Component and More! (Part 2) | CSS-Tricks A CSS-Only Star Rating Component and More! (Part 1) | CSS-Tricks How to Create Wavy Boxes Using CSS Full-Bleed Layout with Modern CSS Fancy Menu Navigation Using Anchor Positioning | CSS-Tricks How to Create a Zig-Zag Box Using CSS How to Create Zig-Zag CSS Loaders Using One Element Custom Progress Element Using Anchor Positioning & Scroll-Driven Animations How to Create Filling CSS Loaders Using One Element How to Create Curved-Edge and Rounded-Edge Shapes Using CSS CSS Tricks That Use Only One Gradient | CSS-Tricks How to create Shapes with Inner Curves using CSS Mask Custom Range Slider Using Anchor Positioning & Scroll-Driven Animations How to Get the Width/Height of Any Element in Only CSS How Keyboard Navigation Works in a CSS Game How To Create Cut-Out Shapes using The clip-path property The Modern Guide For Making CSS Shapes — Smashing Magazine css-shape.com: The Ultimate Collection of CSS-only Shapes ⚡️ Sliding 3D Image Frames In CSS — Smashing Magazine CSS Tricks To Master The clip-path Property Creating Wavy Circles with Fancy Animations in CSS Modern CSS Tooltips And Speech Bubbles (Part 2) — Smashing Magazine Do you need a Tooltip or a Speech Bubble? I have created 100 using CSS 😲 Modern CSS Tooltips And Speech Bubbles (Part 1) — Smashing Magazine Creating Flower Shapes using CSS Mask & Trigonometric Functions CSS Shapes: The Triangle CSS Tricks to add 3D Effects to your Text CSS Responsive Multi-Line Ribbon Shapes (Part 2) — Smashing Magazine CSS Responsive Multi-Line Ribbon Shapes (Part 1) — Smashing Magazine I have made 100+ CSS-only Ribbon Shapes | The Perfect Collection 🎀 How to create a CSS-only infinite scroll animation Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 2) — Smashing Magazine Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 1) — Smashing Magazine How to Create CSS Ribbon Shapes with a Single Element CSS Shapes: The Ribbon Revealing Images With CSS Mask Animations — Smashing Magazine css-loaders.com: The Biggest Collection of Loading Animations (more than 500 🤯) How To Define An Array Of Colors With CSS — Smashing Magazine CSS effects on images II Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images — Smashing Magazine What's your Lucky CSS Pattern? Check It Now! How to Add a CSS Reveal Animation to Your Images Modern Layouts using CSS Grid I created 100+ unique CSS patterns | The best collection 🤩 How to Create a Custom Range Slider Using CSS CSS Shapes: The Heart CSS Shapes: Polygon & Starburst A Text Reveal Animation using CSS CSS Tip: learn CSS the easy way! How to build a CSS-only accordion How to create Breadcrumb Navigation with CSS Different Ways to Get CSS Gradient Shadows | CSS-Tricks A CSS-only responsive Stepper component A Fancy Hover Effect For Your Avatar | CSS-Tricks How to make a zoom effect using CSS Creating a Custom Cursor using CSS CSS Infinite 3D Sliders | CSS-Tricks CSS Infinite Slider Flipping Through Polaroid Images | CSS-Tricks How to create a responsive sidebar menu using CSS CSS Infinite and Circular Rotating Image Slider | CSS-Tricks Making Static Noise From a Weird CSS Gradient Bug | CSS-Tricks CSS Grid and Custom Shapes, Part 3 | CSS-Tricks Fancy Image Decorations: Outlines and Complex Animations | CSS-Tricks Fancy Image Decorations: Masks and Advanced Hover Effects | CSS-Tricks Fancy Image Decorations: Single Element Magic | CSS-Tricks How to create an infinite image slider using CSS How to Create Wavy Shapes & Patterns in CSS | CSS-Tricks How I Made a Pure CSS Puzzle Game | CSS-Tricks How to create a Tooltip/Speech Bubble using CSS CSS Grid and Custom Shapes, Part 2 | CSS-Tricks CSS Grid and Custom Shapes, Part 1 | CSS-Tricks Zooming Images in a Grid Layout | CSS-Tricks How to create a CSS-only loader with one element Exploring CSS Grid’s Implicit Grid and Auto-Placement Powers | CSS-Tricks How to create background pattern using CSS & conic-gradient Single Element Loaders: The Bars | CSS-Tricks
The Complex But Awesome CSS border-image Property — Smashing Magazine
https://www.smashingmagazine.com/author/temani-afif/ · 2024-01-16 · via CSS Articles by Temani Afif

The CSS border-image property is one of those properties you undoubtedly know exists but may not have ever reached for. Or maybe you have reached for it but found all of its slicing logic difficult and cumbersome. That’s because it is! But the property is also capable of some really interesting things if we take the time to understand its syntax. In this article, Temani Afif demonstrates different approaches for using border-image to create clever decorative accents and shapes.

The border-image property is nothing new. Even deprecated Internet Explorer supports it, so you know we’re treading well-charted territory. At the same time, it’s not exactly one of those properties you likely keep close at hand, and its confusing concepts of “slicing” and “outsets” don’t make it the easiest property to use.

I’m here to tell you that border-image is not only capable of producing some incredibly eye-catching UI designs but is also able to accomplish some other common patterns we often turn to other properties and approaches for.

In this article, my plan is to dispel the confusing aspects of border-image without getting into a bunch of theoretical explanations and technical jargon. Instead, we’re going to have fun with the property, using it to create shapes and put a different spin on things like range sliders, tooltips, and title decorations.

By the end of this, I hope that border-image becomes your new favorite property just as it has become mine!

The Concept of Image Borders

There are a few specific aspects of border-image that I think are crucial for understanding how it works.

It’s Easy To Accidentally Override A Border Image

The CSS Backgrounds and Border Module Level 3 specification says border-image should replace any regular border you define, but it’s not always the case. Try the code below, and all you will see is a red border.

/* All I see is a red border */
.element {
  border-image: linear-gradient(blue, red) 1;
  border: 5px solid red;
}

That’s because we’re technically declaring border after border-image. Order really does matter when working with border-image!

/* 👍 */
.element {
  border: 5px solid red;
  border-image: linear-gradient(blue, red) 1;
}

You can already see how this could be confusing for anyone jumping into border-image, especially for the first time. You will also notice that our gradient border has a thickness equal to 5px, which is the border-width we defined.

I make it a personal habit not to use border and border-image together because it helps me avoid overriding the border image I’m trying to create and be able to control the border decoration using only one property (even if both can be used together). So, if you get a strange result, don’t forget to check if you have a border declared somewhere.

It Is Painted Over Backgrounds And Box Shadows

The second tip I want to offer is that border-image is painted above the element’s background and box-shadow but below the element’s content. This detail is important for some of the tricks we will use in later examples. The following Pen demonstrates how a border image is applied in that order:

See the Pen [Showing border-image above background and shadow!](https://codepen.io/t_afif/pen/xxMaVjG) by Temani Afif.

See the Pen Showing border-image above background and shadow! by Temani Afif.

It Has A Complex Syntax

I want to underscore this because I think it’s the reason for the vast majority of confusion. This is the property’s syntax:

border-image: <source> <slice>/<width>/<outset> <repeat>

In this article, the<source> will consist of gradients, although it supports image sources as well. And we are not going to use <repeat> a lot. Let’s re-write the syntax removing the <repeat> and setting a placeholder, *-gradient(), as the source for the time being:

border-image: *-gradient() <slice>/<width>/<outset>

We’ve abstracted a couple of the parameters so that all we’re left with is <slice>, <width>, and <outset>.

The <width> and <outset> work the same as setting border-width, padding, and margin. They each take between one and four values depending on whether you want specific <outset> and <width> values set individually on the element’s edges. Sometimes, I only need to specify the outset, making the width unnecessary. So, you may find me writing something like this:

border-image: *-gradient() <slice>//<outset>

It’s probably the only property where we can have a double slash!

The <slice> also takes between one and four values (either unitless or percentage) as well as an optional fill keyword. This is what makes border-image difficult to understand because it’s not easy to visualize the concept of slices.

Diagramming the areas of a sliced border image.
Figure 1: Illustration of the <slice>, <width>, and <outset> values of the border-image property. (Large preview)

If we were to translate the figure above into code using the provided variables as values, it would look like this:

border-image:
  linear-gradient(...)
  s-top s-right s-bottom s-left / 
  w-top w-right w-bottom w-left /
  o-top o-right o-bottom o-left;

By default, border-image considers the boundaries of the element (illustrated with the blue dotted border in Figure 1) as its area to paint the gradient, but we can change this using the <outset> to increase that area and create an overflow. This is super useful to have “outside” decorations.

Then, the <width> is used to split the area into nine regions, and the <slice> is used to split the source (i.e., the gradient) into nine slices as well. From there, we assign each slice to its corresponding region. Each slice is stretched to fill its assigned region, and if they don’t share equal dimensions, the result is typically a distorted image slice. Later on, we will learn how to control that and prevent distortion.

The middle region is kept empty by default. That said, it is totally possible to use the fill keyword to do what it says and fill the middle region with slice nine (which is always the center slice).

border-image: linear-gradient(...) fill
  s-top s-right s-bottom s-left / 
  w-top w-right w-bottom w-left /
  o-top o-right o-bottom o-left;

I know this was a pretty fast primer on border-image, but I think it’s all we need to do some pretty awesome stuff. Let’s jump into the fun and start experimenting with effects.

Gradient Overlay

Our first experiment is to add a gradient overlay above an existing background. This is a fairly common pattern to improve the legibility of text by increasing the contrast between the text color and the background color.

There are several well-known approaches to setting an overlay between text and content. Here’s one from Chris Coyier back in 2013. And that isn’t even the most widely-used approach, which is likely using pseudo-elements.

But border-image gives us a one-line way to pull it off:

.overlay {
  border-image: fill 0 linear-gradient(#0003,#000); 
}

That’s all! No extra element, no pseudo-element, and no need to modify the background property.

See the Pen [Gradient Overlay with border-image](https://codepen.io/t_afif/pen/vYbdVjb) by Temani Afif.

See the Pen Gradient Overlay with border-image by Temani Afif.

If we dissect the property, we have the <source> (i.e., the gradient) and the <slice> (i.e., fill 0). We didn’t define either the <width> or the <outset>, so they default to 0.

Let’s take that same idea and apply it to the figure we presented earlier when demonstrating the concept of slicing. We’ll replace the variables we used as placeholders with the values from the last example we just looked at.

We have a slice that is equal to 0, so the slices — 1 through 8 — will be empty while the middle slice is filled with the whole gradient. It’s like we have only one slice. The <width> is equal to 0, so regions 1 to 8 are sized to 0, leaving the middle region to what’s left (the whole border-image’s area). And since we did not specify an <outset>, the border-image’s area is equal to the element’s area.

In the end, we have one slice placed in the middle region and eight others we do not see at all. That’s how we end up having our gradient above the element’s background and behind the text.

Let’s try a different syntax but that produces the same output as what we just did.

.overlay {
  border-image: linear-gradient(#0003, #000) 50%/50%; 
}

This time, we are defining a <slice> that is equal to 50%, a <width> that is also equal to 50%, and no <outset>. Slices 1 to 4 each take up one-quarter of the gradient. Slices 5 to 9, meanwhile, are empty. Using the same logic for the regions, we have four regions — 1 to 4 — that each takes up a quarter of the element’s area while the rest of the regions are equal to 0.

In the first approach, we placed one slice in the middle of the element. In this approach, we have four slices, where each is placed in a corner of the element and allowed to fill the entire element.

It’s the same output but a different approach using the same property.

If the slicing concept is tripping you up, we still have plenty of other examples we are going to look at to help you understand it. The trick is to first understand how the gradient is divided into different slices, then how those slices are placed into different regions, which are sized by the <width> and the <outset>. It may take time to grasp the mechanism, but it’s a lot of fun once you do! So, let’s continue to the next example.

Full-Width Backgrounds

Our next example is a common design pattern where we want the background of an element to extend to the screen’s full width. We often refer to this as a “break-out” background because the element typically needs to break outside the constrained width of its parent container in order to stretch across the full screen.

Light pink background extending the full-screen width against a paragraph.
Figure 2: The background is able to “break out” of the parent’s element’s constrained width. (Large preview)

Well, guess what? The border-image property can pull it off with one line of code:

.full-background {
  border-image: conic-gradient(pink 0 0) fill 0//0 100vw;
}

See the Pen [Full screen background color](https://codepen.io/t_afif/pen/oNEaqQX) by Temani Afif.

See the Pen Full screen background color by Temani Afif.

You are probably wondering what’s going on with that conic-gradient(), right? I want a solid color, but unlike the background and background-color properties, border-image does not support color values, so I use a gradient that produces a solid color. For this, I define one color with two color stops inside the gradient.

The type of gradient or what color stops are applied to it doesn’t matter. I prefer conic-gradient() and two zeros because it simply offers the smallest syntax to get a solid color as a result.

Now, let’s dissect that line of code. We have a <slice> that is equal to 0, no <width> (it is implicitly equal to 0), and this time the <outset> is equal to 0 100vw which increases the border-image’s area from the left and right side by 100% of the viewport’s width (100vw).

We could technically use a value smaller than 100vw since the space we need to cover will most likely be smaller, but using a larger value is always good to make sure we consider all the possibilities. And border-image doesn’t trigger scrolling, so don’t worry about using big values!

Value of 100vw, which is larger than the screen width
Figure 3: Using a large value guarantees that the background is always wide enough. (Large preview)

If you compare what we just did with the gradient overlay example, the <outset> is the only difference between the implementations. Other than that, we have a single slice placed in the middle region that covers the entire area we extended to the edge of the screen.

We are not limited to a solid color, of course, since we are working with gradients.

See the Pen [Full screen background coloration](https://codepen.io/t_afif/pen/NWoLeWW) by Temani Afif.

See the Pen Full screen background coloration by Temani Afif.

We can even get a little fancy by slanting the backgrounds to produce an interesting page design.

See the Pen [CSS-only full screen slanted background](https://codepen.io/t_afif/pen/zYmpdeK) by Temani Afif.

See the Pen CSS-only full screen slanted background by Temani Afif.

The “tricky” part is that I have combined border-image with clip-path:

.slant {
  --a: 3deg; /* control the angle (it should be small) */
  
  border-image: conic-gradient(pink 0 0) fill 0//9999px;
  clip-path: 
    polygon(
      -9999px calc(tan(var(--a)) * 9999px),
      9999px calc(tan(var(--a)) * -9999px),
      calc(100% + 9999px) calc(100% - tan(var(--a)) * 9999px),
      calc(100% - 9999px) calc(100% + tan(var(--a)) * 9999px)
    );
}

This time, we have a rather large <outset> extending in all directions. This forces the color to overflow the element’s boundaries, which allows us to reach for the CSS clip-path property to cut out the shape.

Comparing the background before and after clipping.
Figure 4: Clipping the background creates a slanted appearance. (Large preview)

Fancy Headings

Another thing we can use border-image for is decorating headings with fancy borders. Let’s start with the exact same implementation we used for the full-width backgrounds. Only this time, we’re replacing the conic-gradient() with a linear-gradient():

.full-background {
  border-image: linear-gradient(0deg, #1095c1 5px, lightblue 0) fill 0//0 100vw;
}

Now we apply this to an <h1> element:

See the Pen [Full screen gradient coloration on title](https://codepen.io/t_afif/pen/JjxawEv) by Temani Afif.

See the Pen Full screen gradient coloration on title by Temani Afif.

Nothing surprising here. We’re basically establishing a gradient with a sharp color stop that creates a border-like appearance along the bottom edge of the heading, extending the full width of the screen. But what if we make one of the colors transparent and define a big <outset> in only one direction? This produces a bottom border that extends to the edge of the screen in a single direction rather than both directions.

See the Pen [CSS only extended underline](https://codepen.io/t_afif/pen/yLvwgNy) by Temani Afif.

See the Pen CSS only extended underline by Temani Afif.

That’s a simple pattern, but it could be a nice design accent. Still using one line of code:

.full-line {
  border-image: linear-gradient(0deg, #1095c1 5px, #0000 0) fill 0//0 100vw 0 0;
}

We can actually accomplish this another way:

.full-line {
  border-image: conic-gradient(#1095c1 0 0) fill 0/calc(100% - 8px) 0 0 0/0 100vw 0 0;
}

This defines the size of the top regions to be equal to 100% - 8px while the rest of the regions are equal to 0. If you refer back to the first figure, it means we are making the height of region five equal to 100% - 8px, so the middle region will have only 8px of height, and since the slice is still 0, we only have the middle slice placed inside that 8px of space.

The height of the region is set to the full height of the element, minus 8px at the bottom edge.
Figure 5: The height of the region is set to the full height of the element, minus 8px at the bottom edge. (Large preview)

So, that’s two different ways to get the same effect using the same border-image syntax. We can actually get this a third way as well:

.full-line {
  border-image: conic-gradient(#1095c1 0 0) 0 0 1 0/0 0 8px 0/0 100vw 0 0;
}

This time, I have defined a bottom slice equal to 1 (unitless values are computed as pixels), which produces two slices, the seventh (bottom center) and the ninth (center). From there, I have set the seventh region to a height of 8px. Note that I am not using the fill keyword this time, so the middle region is not filled like it was last time. Instead, we only fill the seventh region that takes up 100% of the boder-image’s area and 8px of its height.

Filling the seventh region that is 8px tall with a solid color.
Figure 6. (Large preview)

You’re wondering why I am defining a slice equal to 1, right? The goal is to have only two slices: the seventh (bottom center) and the ninth (middle), and since we are applying a solid color, the size doesn’t matter. That’s why I used 1; a small positive value. Any value will work (e.g., 0.5, 2, 100, 50%, 76%, and so on); it’s just that 1 is shorter to type. Remember that the slice will get stretched within its region, so 1px is enough to fill the whole region.

Here’s the deal: The slice value doesn’t really matter when working with a solid coloration. In most cases, the value winds up being 0 (empty) or 1 (filled). You can think of it as binary logic.

We could do this a fourth way!

.full-line {
  border-image: conic-gradient(#1095c1 0 0) 0 1 0 0/calc(100% - 8px) 100% 0 0/0 100vw 0 0;
}

I’ll let you do the work to figure out how the above CSS works. It’s a good opportunity to get a feel for slicing elements. Take a pen and paper and try to identify which slices we are using and which regions will be filled.

One thing that makes border-image a complex property is all the different ways to achieve the same result. You can wind up with a lot of different combinations, and when all of them produce the same result, it’s tough to form a mental model for understanding how all of the values work together.

Even though there is no single “right” way to do these heading borders, I prefer the second syntax because it allows me to simply change one color value to establish a “real” gradient instead of a solid color.

.full-line {
  border-image: repeating-linear-gradient(...) fill 0 /
    calc(100% - var(--b)) 0 0/0 100vw 0 0 repeat;
}

See the Pen [CSS only extended underline with gradient](https://codepen.io/t_afif/pen/mdXYyRg) by Temani Afif.

See the Pen CSS only extended underline with gradient by Temani Afif.

Notice the repeat keyword in that last example. I talked earlier about how a slice can be set to a size that is different than its corresponding region, and that could lead to a distorted border image. This isn’t an issue when dealing with a solid color. Using a real gradient, however, is where distortion might occur. Fortunately, the fix in most cases is to set repeat at the end of the border-image declaration (stretch is the default value).

If repeat doesn’t seem to work, then it’s possible there is an issue somewhere else in the code… or perhaps you have reached the limit of what border-image can do. It’s a powerful property, but like any other, it has its limitations.

Heading Dividers

Since we were just making bottom borders for headings in the last example, I figure we can do a variant of that by drawing the border through the heading.

See the Pen [Horizontal lines around your title](https://codepen.io/t_afif/pen/BaYXdmM) by Temani Afif.

See the Pen Horizontal lines around your title by Temani Afif.

This can be a nice way to emphasize a heading, especially those in an article body. Here is the pertinent code:

h2 {
  --s: 3px;   /* the thickness */
  --c: red;   /* the color */
  --w: 100px; /* the width */
  --g: 10px;  /* the gap */

  border-image: 
    linear-gradient(
      #0000      calc(50% - var(--s)/2),
      var(--c) 0 calc(50% + var(--s)/2),
      #0000 0) 
    0 1 / 0 var(--w) / 0 calc(var(--w) + var(--g));
}

This example is putting CSS variables to use so we have some flexibility to re-configure the border image and create variations of the pattern. But before reading the explanation of how this works, please take a moment to visualize the result using what you have learned so far. Try to identify the slices, the regions, and their dimensions.

Ready? Here’s how it works.

We have a slice equal to 0 11px each from the left and right. This establishes slices eight (center-right) and six(center-left) with a width of 1px while the remaining space is reserved for the ninth (center) slice. We are not using fill, so we don’t really care about the ninth slice since it won’t get painted.

The width (--w) is used to set the size of regions six and eight. We need the same amount inside the <outset> to make sure those two regions are outside of the element’s boundaries. Another variable, --g, is added to the outset formula to control the gap between the text and the decoration.

The gradient is similar to the one we used for the bottom heading borders in the last section. Only this time, the color is in the center instead of the bottom, and its size is controlled using the --s variable.

Showing the 6 and 8 slices and their corresponding regions.
Figure 7. (Large preview)

Let’s try another syntax for the same effect:

h2 {
  --s: 3px;   /* the thickness */
  --w: 100px; /* the width */
  --g: 10px;  /* the gap */
  border-image: 
     conic-gradient(red 0 0) 
     0 50%/calc(50% - var(--s)/2) var(--w)/0 calc(var(--w) + var(--g));
}

The top and bottom values of the <slice> are equal to 0, and the left and right ones are equal to 50%. This means that slices six and eight share the gradient. All the other slices — including the center — are empty.

As far as the regions go, the top and bottom regions (consisting of regions 1, 5, and 2 at the top and regions 4, 7, and 3 at the bottom) have a height equal to 50% - var(--s)/2 leaving the --s variable as a height for the remaining regions (6, 8, and 9). The right and the left regions have a width equal to the --w variable. Since slices 6 and 8 are the only ones that are filled, the only regions we need to care about are 6 and 8. Both have a height equal to the border’s thickness, --s, and a width equal to --w.

I think you know how the rest of the story goes.

Showing slices 6 and 8 applied to their corresponding regions.
Figure 8. (Large preview)

Notice I am using 50% as a slice. It demonstrated how any value does the job, as we discussed in the last section when I explained why I chose to use a value of 1 but also to prepare for the next effect where I will be using a real gradient:

See the Pen [Horizontal lines around your title with gradient coloration](https://codepen.io/t_afif/pen/RwvYvGr) by Temani Afif.

See the Pen Horizontal lines around your title with gradient coloration by Temani Afif.

When it comes to real gradients, the value of the slice is important, and sometimes you need very precise values. To be honest, this can be very tricky, and I even get lost trying to figure out the right value.

Let’s end this section with more examples of title decorations. When combined with other properties, border-image can make really nice effects.

See the Pen [Fancy title divider with one element](https://codepen.io/t_afif/pen/VwXOmjW) by Temani Afif.

See the Pen Fancy title divider with one element by Temani Afif.

See the Pen [Fancy title divider with one element](https://codepen.io/t_afif/pen/zYWQmyo) by Temani Afif.

See the Pen Fancy title divider with one element by Temani Afif.

More Examples

Now that we’ve seen several detailed examples of how border-image, I’m going to drop in several other examples. Rather than explaining them in great detail, try to explain them in your own words by inspecting the CSS, and use these as inspiration for your own work.

Infinite Image Decorations

When it comes to images, border-image can be a lifesaver since we don’t have access to pseudo-elements. Here are some cool infinite decorations where we can have a touch of 3D effect.

See the Pen [Infinite image shadow](https://codepen.io/t_afif/pen/XWoNdGK) by Temani Afif.

See the Pen Infinite image shadow by Temani Afif.

See the Pen [Infinite image shadow II](https://codepen.io/t_afif/pen/mdvaeoq) by Temani Afif.

See the Pen Infinite image shadow II by Temani Afif.

See the Pen [Infinite image stripes shadow](https://codepen.io/t_afif/pen/yLZwLKj) by Temani Afif.

See the Pen Infinite image stripes shadow by Temani Afif.

See the Pen [3D trailing shadow for images](https://codepen.io/t_afif/pen/mdQwgMO) by Temani Afif.

See the Pen 3D trailing shadow for images by Temani Afif.

If you check the code in these examples, you will find they share nearly the same structure. If you have trouble recognizing the pattern, please don’t hesitate to leave a comment at the end of this article, and I would be happy to point it out.

Custom Range Slider

I wrote a detailed article on how to create the following example, and you can refer to it for range slider variations using the same technique.

See the Pen [CSS only custom range sliders](https://codepen.io/t_afif/pen/KKGpmGE) by Temani Afif.

See the Pen CSS only custom range sliders by Temani Afif.

I used border-image and styled only the “thumb” element. Range inputs are known to have different implementation cross-browser, but the “thumb” is common between all of them.

Ribbon Shapes

In case you missed it, I have created a collection of more than 100 single-element ribbon shapes, and some of them rely on border-image. I call them the “infinite ribbons.”

See the Pen [Full screen Ribbon title](https://codepen.io/t_afif/pen/rNqJYrZ) by Temani Afif.

See the Pen Full screen Ribbon title by Temani Afif.

See the Pen [Infinite Ribbon Shapes](https://codepen.io/t_afif/pen/NWoRJMy) by Temani Afif.

See the Pen Infinite Ribbon Shapes by Temani Afif.

Heart Shapes

I have written about CSS heart shapes using different approaches, and one of them uses a border-image technique.

.heart {
  width: 200px;
  aspect-ratio: 1;
  border-image: radial-gradient(red 69%,#0000 70%) 84.5%/50%;
  clip-path: polygon(-42% 0,50% 91%, 142% 0);
}

See the Pen [Heart shape using border-image](https://codepen.io/t_afif/pen/MWPOJpP) by Temani Afif.

See the Pen Heart shape using border-image by Temani Afif.

The interesting part here is the slice that is equal to 84.5%. That is a bigger value than 50%, so it may seem incorrect since the total exceeds 100%. But it’s perfectly fine because slices are able to overlap one another!

When using values bigger than 50%, the corner slices (1, 2, 3, and 4) will share common parts, but the other slices are considered empty. Logically, when using a slice equal to 100%, we will end with four slices containing the full source.

Here is an example to illustrate the trick:

See the Pen [Overview of the slice effect](https://codepen.io/t_afif/pen/jOdemWL) by Temani Afif.

See the Pen Overview of the slice effect by Temani Afif.

The slider will update the slice from 0% to 100%. On the left, you can see how the corner slices (1-4) grow. Between 0% and 50%, the result is logical and intuitive. Bigger than 50%, you start having the overlap. When reaching 100%, you can see the full circle repeated four times because each slice contains the full gradient, thanks to the overlap.

It can be confusing and not easy to visualize, but overlaps can be really useful to create custom shapes and fancy decorations.

What about a simple tooltip shape with only two properties? Yes, it’s possible!

See the Pen [A simple Tooltip using 2 CSS properties](https://codepen.io/t_afif/pen/ExrEXoO) by Temani Afif.

See the Pen A simple Tooltip using 2 CSS properties by Temani Afif.
.tooltip {
  /* triangle dimension */
  --b: 2em; /* base */
  --h: 1em; /* height*/

  border-image: conic-gradient(#CC333F 0 0) fill 0//var(--h);
  clip-path: 
    polygon(0 100%,0 0,100% 0,100% 100%,
      calc(50% + var(--b)/2) 100%,
      50% calc(100% + var(--h)),
      calc(50% - var(--b)/2) 100%);
}

This is only a simple example among many tooltip shapes I am exploring in another article where I also use the border-image property as well for visual effects.

Filling Border Radius

Unlike most decorative border properties (e.g., box-shadow, outline, border, and so on), border-image doesn’t respect border-radius. The element is still a box, even if we’ve rounded off the corners. Other properties will recognize the visual boundary established by border-radius, but border-image bleeds right through it.

That could be a drawback in some instances, I suppose, but it’s also one of the quirky things about CSS that can be leveraged for other uses like creating images with inner radius:

See the Pen [Inner radius to image element](https://codepen.io/t_afif/pen/abMvjZj) by Temani Afif.

See the Pen Inner radius to image element by Temani Afif.

Cool, right? Only one line of code makes it happen:

img {
  --c: #A7DBD8;
  --s: 10px; /* the border thickness*/

border-image: conic-gradient(var(--c) 0 0) fill 0 // var(--s);
} 

We can even leave the center empty to get a variation that simply borders the entire element:

See the Pen [Rounded images inside squares](https://codepen.io/t_afif/pen/gOqBWvg) by Temani Afif.

See the Pen Rounded images inside squares by Temani Afif.

Conclusion

Did you know border-image property was such a powerful — and flexible — CSS property? Despite the challenge it takes to understand the syntax, there are ways to keep the code clean and simple. Plus, there is often more than one “right” way to get the same result. It’s a complicated and robust CSS feature.

If the concepts of slicing and defining regions with border-image are still giving you problems, don’t worry. That’s super common. It took me a lot of time to fully understand how border-image works and how to use it with different approaches to the syntax. Give yourself plenty of time, too. It helps to re-read things like this article more than once to let the concepts sink in.

Complexities aside, I hope that you will add border-image to your toolbox and create a lot of magic with it. We can do even more with border-image than what was demonstrated here. I actually experiment with this sort of stuff frequently and share my work over at my CSS Tip website. Consider subscribing (RSS) to keep up with the fun and weird things I try.

Special thanks to @SelenIT2, who pushed me to explore this property and wrote an excellent article on it.

Smashing Editorial (gg, yk)