Tag: Border

How to Add a Double Border to SVG Shapes

Let’s say someone asks you to add a double border to some random geometric SVG shapes. For some reason, you can’t use any graphic editor — they need to be generated at runtime — so you have to solve it with CSS or within the SVG syntax.

Your first question might be: Is there anything like stroke-style: double in SVG? Well, the answer is not yet and it’s not that easy. But I’ll attempt it anyway to see what methods I can uncover. I’ll explore the possibilities of three different basic shapes: circle, rectangle, and polygon. Pointing the ones that can keep a transparent color in the middle of the two lines.

Spoiler alert: all the results have their downsides, at least with CSS and SVG, but let me walk you through my intents.

The simple solutions

These don’t work with all shapes, but they are the easiest of the solutions.

outline and box-shadow

The CSS properties outline and box-shadow only apply to the bounding box of the shape or SVG, and so both are great solutions only for squares and rectangles. They also allow flexible colors using custom properties.

It only takes two lines of CSS with outline, plus it keeps the background color visible through the shape.

  • 🙁 Solution only for one shape.
  • ✅ Simple code
  • ✅ Borders are smooth
  • ✅ Transparent background

box-shadow only needs one line of CSS, but we have to make sure that each shape has its own SVG as we can’t apply box-shadow directly to the shapes. Another thing to consider is that we have to apply the color of the background in the declaration.

  • 🙁 Solution only for one shape
  • ✅ Simple code
  • ✅ Borders are smooth
  • 🙁 No transparent background

SVG gradients

SVG radial gradients only work on circles ☺️. We can directly apply the gradient on the stroke, but it’s better to use variables as we have to declare the colors many times in the code.

  • 🙁 Solution only for one shape
  • ✅ Simple code
  • 🙁 Borders are smooth
  • 🙁 No transparent background

Solutions for all shapes

These will work with all shapes, but the code could become bloated or complex.

filter: drop-shadow()

Finally, one solution for all shapes! We must have each shape in its own <svg> since the filter won’t apply directly to the shapes. We are using one declaration in CSS and have flexible colors using variables. The downside? The borders don’t look very smooth.

  • ✅ One solution for all shapes
  • ✅ Simple code
  • 🙁 Borders look pixelated
  • 🙁 No transparent background

SVG filters

This is a very flexible solution. We can create a filter and add it to the shapes through SVG’s filter attribute. The complicated part here is the filter itself. We’ll need three paintings, one for the outside border, one for the background flood, and the last one to paint the shape on the front. The result looks better than using drop-shadow, but the borders are still pixelated.

  • ✅ One solution for all shapes
  • 🙁 Complex code
  • 🙁 Borders look pixelated
  • 🙁 No transparent background

Reusing shapes

There are a couple of possible options here.

Option 1: Transforms

This solution requires transforms. We place one figure over the other, where the main figure has a fill color and a stroke color, and the other figure has no fill, a red stroke, and is scaled and repositioned to the center. We defined our shapes on the <defs>. The trick is to translate half of the viewBox to the negative space so that, when we scale them, we can do it from the center of the figure.

  • ✅ One solution for all shapes
  • 🙁 Duplicated code
  • ✅ Borders are smooth
  • ✅ Transparent background
Option 2: <use>

I found a clever solution in the www-svg mailing list by Doug Schepers that uses SVG <use>. Again, it requires defining the shapes once and referring to them twice using <use>. This time the main shape has a bigger stroke. The second shape has half the stroke of the main shape, no fill, and a stroke matching the background color.

  • ✅ One solution for all shapes
  • 🙁 Duplicated code
  • ✅ Borders are smooth
  • 🙁 No transparent background

Here are the full results!

Just so you have them all in one place. Let me know it you can think of other possible solutions!

Solution All shapes Simple code Smooth borders Transparent background
outline 🙁
box-shadow 🙁 🙁
SVG gradients 🙁 🙁 🙁
filter: drop-shadow() 🙁 🙁
SVG filters 🙁 🙁 🙁
Reusing shapes:
Tranforms
🙁
Reusing shapes:
<use>
🙁 🙁

The post How to Add a Double Border to SVG Shapes appeared first on CSS-Tricks.

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

CSS-Tricks

, ,

CSS Border Font

Every letter in this “font” by Davor Suljic is a single div and drawn only with border. That means employing some trickery like border-radius with exotic syntax like border-radius: 100% 100% 0 0 / 37.5% 37.5% 0 0; which rounds just the top of an element with a certain chillness that works here. Plus, using pseudo-elements. I love all the wacky variations with colors, shadows, and border styles, leaning into the limits of CSS.

Drawing things with CSS has long fascinated people. Icons are a popular choice (famously, Nicolas Gallagher’s Pure CSS GUI icons from 2010), since we can draw so many shapes with CSS without even needing to lean on the all-powerful clip-path.

But as Lynn Fisher has taught us, a single div is barely a limitation at all.

Direct Link to ArticlePermalink


The post CSS Border Font appeared first on CSS-Tricks.

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

CSS-Tricks

,
[Top]

Animating a CSS Gradient Border

This little trick for gradient borders is super useful:

.border-gradient {   border: 5px solid;   border-image-slice: 1;   border-image-source: linear-gradient(to left, #743ad5, #d53a9d); }

Here’s some basic demos from our article on the subject. Sephanie Eckles was sharing around the idea with more detail. Bramus Van Damme saw that and stretched it a bit by adding, then animating an angle to the gradient. Like:

div {   --angle: 0deg;   /* … */   border-image: linear-gradient(var(--angle), green, yellow) 1;   animation: 10s rotate linear infinite; }  @keyframes rotate {   to {     --angle: 360deg;   } }

But wait! That’s not actually going to animate as-is. The browser doesn’t know that 360deg is an actual angle value, and not just some random string. If it did know it was an angle value, it could animate it. So, tell it:

@property --angle {   syntax: '<angle>';   initial-value: 0deg;   inherits: false; }

See Bramus’ article for the demos there. Bonafide CSS trick. I can’t wait for more support for @property (Chrome only, as I write), because it really unlocks some cool CSS trickery. Animating numbers visually, for example.

Direct Link to ArticlePermalink


The post Animating a CSS Gradient Border appeared first on CSS-Tricks.

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

CSS-Tricks

, ,
[Top]

What Happens When Border Radii Overlap?

I’d wager that most times we’re rounding box corners in CSS, we’re applying a uniform border-radius value across the border. It’s a nice touch of polish in many designs. But there are times when we might want different radii for different corners. Easy, right? That way the property takes four values. Well, as it turns out, it’s actually possible to paint ourselves into a corner because rounded borders are capable of overlapping one other.

Many of us know the common “999em hack” for getting a “pill-shaped” rectangle:

We set the border-radius to an absurdly large number, like 999em or 999vmax, and instead of becoming some kind of impossible, Escher-esque möbius strip, the corners are nicely rounded off to form a semicircle. This is convenient because it means we don’t have to know the dimensions of the rectangle to achieve this effect — it “just works.”

The origins of this trick are murky to me, but I found an early example in a comment on Lea Verou’s blog by David Baron.

But, like many “hacks”, we can encounter some odd behavior in certain edge cases. For instance, why does that work when this doesn’t:

We want the right side of the rectangle to be “pill-shaped,” and the left side to have corners rounded to 40px. But our 40px corners are gone! Where did they go?

Hey, those left corners should be slightly rounded!

The answer is that they didn’t go anywhere; the browser has just reduced their values so close to zero that they merely look like they’re gone.

The browser is diverging somehow from the values we requested, but when and how does it decide to step in? Let’s check the spec:

Let f = min(Li/Si), where i ∈ {top, right, bottom, left}, Si is the sum of the two corresponding radii of the corners on side i, and Ltop = Lbottom = the width of the box, and Lleft = Lright = the height of the box. If f < 1, then all corner radii are reduced by multiplying them by f.

Ah, that explains it! Have a great rest of your week! :wipes hands conclusively:

…I’m joking, of course. That requires a little decoding, so let’s look at it two ways, mathematically and geometrically. Always keep in mind that the purpose of this formula is to prevent radius overlap. In fact, that’s why the “999em hack” works in the first place!

Here’s what I mean.

In plain English, the browser is essentially thinking: “Shrink all radii proportionally until there is no overlap between them.” (Note that it’s the radii that mustn’t overlap; the circles they form may indeed overlap.)

But a computer doesn’t understand English, so what the formula does is this.

First, it calculates the ratio of the length of each side of the rectangle to the sum of the radii that touch it. So, in our standard “pill hack” that works out to:

[Width of Side] / [Adjacent Border Radius 1 + Adjacent Border Radius 2] Top: 200px / (400px + 400px) = 0.25 Right: 100px / (400px + 400px) = 0.125 Bottom: 200px / (400px + 400px) = 0.25 Left: 100px / (400px + 400px) = 0.125

Then it multiplies all of the radii by the smallest of these ratios. The smallest ratio is 0.125, so we’ll multiply that by our initial 400px radii:

400px * 0.125 = 50px

That leaves all our radii at 50px. For a rectangle whose shortest sides are 100px, this gives us a perfect pill shape. Cool! Take a look at the following animation:

(To make things easier to see, we’re using 400px here for our “absurdly large” radii rather than 999em; they’ll overlap as long as they are at least half the length of the shortest side of the rectangle.)

The circles representing the radii we specified start out at their requested size, then shrink by the ratio dictated by the formula above. What’s important to note is that they all shrink by the same ratio. It’s perhaps more intuitive here, since they all start out at the same size anyway.

Now let’s go back to our “broken” example that got everything started.

What’s going on here? Let’s try a less extreme example to show border radii that are affected by this shrinking, but not to the extent that they virtually disappear:

We can see there that we’re not getting the 40px radii we’re asking for in the top-left and bottom-left corners, but we are getting something. Let’s work through that formula again, first finding the ratios between all the sides and their adjacent radii:

Top: 200px / (40px + 400px) = 0.455 Right: 100px / (400px + 400px) = 0.125 Bottom: 200px / (40px + 400px) = 0.455 Left: 100px / (40px + 40px) = 1.25

Again, our lowest ratio there is 0.125, so we multiply all the specified radii by that amount, giving us 50px radii for the right corners and 5px radii for the left corners.

What the formula is ensuring here is that the two large radii on the right side of the rectangle don’t overlap, but in doing so, has shrunk the small radii on the left side of the rectangle more than they “need to be” shrunk to prevent radius overlap on the top, bottom, and left sides.

Here’s a richer example that shows what happens in different circumstances. Play around with some of the values to see what happens. Again, the large sizes are the radii we specified in code, and the small sizes are how the browser reconciles them to prevent overlap.

Why would the Oz-like spec makers decide on doing things this way? Why not shrink the larger border radii first, rather than shrinking all radii from the start?

I can’t read their minds, of course, but the benefit of this approach is that the radii maintain their proportions to one another. If we were to instruct the browser to decrease the largest radii until there was no overlap or until it was equal to the second largest radii (whichever came first) and repeat, then our “hybrid pill hack” would have worked; but there are cases where you could end up with four equal radii when the user had asked for very different sizes. In other words, the implementation has to be “unfaithful” to the numbers one way or the other, and this is the way they chose (wisely, I think).

Thanks to my colleague Catherine for first noticing this “disappearing radii” issue!


The post What Happens When Border Radii Overlap? appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,
[Top]

How to Make Repeating Border Images

I just saw this cool little site from Max Bittker: broider. You design an image on a 9-slice grid (except the middle part) and it will produce an image for you to use with border-image along with the CSS to copy and paste.

Check out my little design:

The areas of the image ultimately output to a base64 PNG file with the designs in each area. For example, if you just drew in the top-center quadrant, the generated PNG looks like this:

Which gives you a single border like this, which might be just what you want:

On the new ShopTalk Show website, we have a similar effect in a few places, like this:

We did that in a slightly different way. Rather than border-image, we used a background-image and background-repeat: round; That way we could use an image in pretty much the same way, only we had to take the extra step of placing an “inner” element in order to knock out the middle (so it fakes a border).

Like this:

Looking at it now, we probably should have just used border-image, as it can do the same thing and is a bit cleaner. Our Almanac page has more examples.

The post How to Make Repeating Border Images appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements

I recently had to craft a newspaper-like design that featured multiple row and column spans with divider lines in between them. Take a look at the mockup graphic here and see if it makes you sweat at all. If you’re like me, you have been around a while and know just how difficult this would have been with old layout techniques.

Newspaper design with line dividers between cells

The project came with a few requirements:

  • Show the outlines of the grid
  • Columns can be wider, or longer than others
  • Divider lines must be shown between the various blocks

CSS Grid: Teaching an old layout new tricks

Newspaper layouts can cause headaches because everyday CSS is one-dimensional, meaning that elements flow on either a horizontal or vertical axis. Even modern flexbox layout is still uni-directional.

For a layout like this, we would almost want the properties that good ol’ HTML tables once provided: things like row and column spans to stretch cells in all directions. We would also want the benefits of modern day CSS, with all the responsiveness and flexible boxes that can grow to fill available space.

CSS grid combines the best of tables with the best of flexible boxes. In fact, grid’s even better because it provides the grid-gap property for creating gutters between cells while taking available space into account. Powerful as this may be, how can we create divider-lines exactly in the middle of those gutters?

Let’s look at three techniques to make that happen.

What we’ll create

First, we will build a simplified version of the newspaper design that’ll help illustrate the crux of the three different techniques that we’re going to cover. A deceptively easy design, one would say.

Column and row spans in a CSS grid layout

Technique 1: The faux column

This solution creates “faux” columns that allow us to draw vertical lines, and then place a grid on top. Horizontal dividers are painted if needed. The “faux” columns are created by using pseudo selectors in the grid container.

<div class="frontpage">   <div class="fp-cell fp-cell--1">     <div class="fp-item">1</div>   </div>   <div class="fp-cell fp-cell--2">     <div class="fp-item">2</div>   </div>   <div class="fp-cell fp-cell--3 fp-cell--border-top">     <div class="fp-item">3</div>   </div>   <div class="fp-cell fp-cell--4 fp-cell--border-top">     <div class="fp-item">4</div>   </div> </div>

See the Pen
Newspaper-design, ‘faux-column’ technique
by Marco Troost (@marco-troost)
on CodePen.

Setting up the lines between the columns

Let’s create a three-column container using display: grid and pseudo-selectors (:before and :after) to create two columns that fill 100% of the container’s height.

.frontpage {   position: relative;   display: grid;   /* Three columns */   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  /* Two faux columns */ .frontpage:before, .frontpage:after {   position: absolute;   top: 0;   height: 100%;   content: '';   width: calc(33.3% - 4px); }  .frontpage:before {   left: 0;   border-right: 1px solid #DADCE0; }  .frontpage:after {   right: 0;   border-left: 1px solid #DADCE0; }

Note: 33% of the container doesn’t take the gutter width into account, so you’ll have to compensate accordingly.

This is calculated as:

33% minus (gutter-width divided by (amount of gutters times amount of gutters)) divided by amount of gutters)

Or, with actual numbers:

33% - (32 / (2* 2)) / 2 = 4

We could use one pseudo-selector instead:

.frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-column-gap: 32px;   border: 1px solid transparent;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow: hidden; }  .frontpage:before {   box-sizing: border-box;   position: absolute;   top: 0;   height: 100%;   content: '';   left: calc(33.3% - 5.3px);   width: calc(33.3% + 10.7px);   border-left: 1px solid #DADCE0;   border-right: 1px solid #DADCE0; }

See the Pen
Newsgrid-layout ‘faux-columns’ (using only :before)
by Marco Troost (@marco-troost)
on CodePen.

Note: A different calculation is needed when using only one pseudo-selector: One for positioning, and one for width.

The width is calculated as:

33% plus (amount of gutters times gutter-width) / (amount of gutters times amount of columns)

Again, with actual numbers:

33% + (2 * 32) / (2 * 3) = 10.7

The position is calculated as:

33% minus (amount of gutters times gutter-width) / (amount of gutters times amount of columns) divided by 2)

Making the grid

The design consists of four blocks of content. We’re going to place them in the container and give them a modifier class for future reference while making sure their z-index is higher than the pseudo-selectors of the grid.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3"></div>   <div class="fp-cell fp-cell--4"></div> </div>

Now let’s set the background color for the cells (.fp-cell) to white. This way, the vertical lines won’t show through. We can also set the vertical padding for the cell to 16px in order to match half of the gutter.

The first and second content blocks should get their own unique spans as shown in the design. The first block spans all the way down and the second block spans the second and third columns.

.fp-cell {   position: relative;   z-index: 2;   padding: 16px 0;   background-color: #fff; }  /* Span all the way down! */ .fp-cell--1 {   grid-row: 1 / span 2; }  /* Span the second and third columns */ .fp-cell--2 {   grid-column: 2 / span 2; }

Vertical line dividers

If you look at the design, only the last two cells need a horizontal border. We can give ’em a sweet modifier class.

<div class="frontpage">   <div class="fp-cell fp-cell--1"></div>   <div class="fp-cell fp-cell--2"></div>   <div class="fp-cell fp-cell--3 fp-cell--border-top"></div>   <div class="fp-cell fp-cell--4 fp-cell--border-top"></div> </div>
.fp-cell--border-top:before {   content: '';   position: absolute;   top: 0;   left: -16px;   right: -16px;   border-top: 1px solid #DADCE0; }

The negative margins are half of the gutter width.

Technique #2: Using background-color

Another way to create the dividers is to utilize the grid-gap property. This solution doesn’t necessarily create a “real” distance between cells, but rather leaves some blank space where the background-color of the grid can shine through. The gutter width is delegated to padding within the grid cells.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">       <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   overflow-x: hidden;   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   margin: 0 -16px;   background-color: #DADCE0; }  .fp-cell {   background-color: #fff;   padding: 16px; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, background-color technique
by Marco Troost (@marco-troost)
on CodePen.

Since all cells have an extra 16px of horizontal padding, the grid needs to be offset by just as much. A wrapper container will take care of the overflow.

<div class="container">   <div class="frontpage">   <!-- ... -->   </div> </div>
.container {   border-top: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr;   grid-gap: 1px;   background-color: #DADCE0;   margin: 0 -16px; }

Technique #3: Creating a cell border

This solution appends a right and bottom border to each cell. Like the last example, the grid-gap is mimicked by adding padding to the cell content. That means it also needs to be wrapped in an extra container.

<div class="container">   <div class="frontpage">     <div class="fp-cell fp-cell--1">       <div class="fp-item">1</div>     </div>     <div class="fp-cell fp-cell--2">       <div class="fp-item">2</div>     </div>     <div class="fp-cell fp-cell--3">         <div class="fp-item">3</div>     </div>     <div class="fp-cell fp-cell--4">       <div class="fp-item">4</div>     </div>   </div> </div>
.container {   border-top: 1px solid #DADCE0;   overflow-x: hidden; }  .frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }  .fp-cell {   padding: 16px;   background-color: #fff;   border-right: 1px solid #DADCE0;   border-bottom: 1px solid #DADCE0; }  .fp-cell--1 {   grid-row: 1 / span 2; }  .fp-cell--2 {   grid-column: 2 / span 2; }  .fp-cell--3 {   grid-column: 2; }  .fp-item {   background-color: #efefef;   display: flex;   align-items: center;   justify-content: center;   min-height: 200px;   height: 100%; }

See the Pen
Newspaper-design, ‘cell-border’-technique
by Marco Troost (@marco-troost)
on CodePen.

As mentioned, each cell is given a border on the right and on the bottom. The main trick here is the use of the (asymmetrical) negative margin on the grid. This is needed to compensate for the cell’s right border.

.frontpage {   margin: 0 -17px 0 -16px;   position: relative;   display: grid;   grid-template-columns: 1fr 1fr 1fr; }

Conclusion

Occam’s razor stipulates that the simplest solution wins. In our case, that’s technique number two. But then again, the other solutions have plenty of merit and they could prove useful if, for example, access to the DOM is not possible.

All of these techniques will work. Choosing the right one depends on your use case. The first technique uses the actual grid-gap property to create the gaps, but the others are perhaps easier to understand at a glance… and perhaps easier to maintain as well.

The post Techniques for a Newspaper Layout with CSS Grid and Border Lines Between Elements appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]