Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-borders][css-images] Properly address border image use cases, and kill border-image with fire #9714

Open
LeaVerou opened this issue Dec 15, 2023 · 11 comments

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Dec 15, 2023

Background

Overall border-image is a mess, and most authors won't touch it with a bargepole unless they really have to (per the 2022 Almanac it is used on < 7% of pages, which seems way lower than the frequency of actual border image use cases).
It doesn't cover enough related use cases, and even when it does, its syntax is confusing.
Several issues exist to patch some of its holes, either by tweaking border-image itself, or by adding syntax to other parts of CSS to address them, e.g.:

Its syntax also has issues:

Fixing border-image

It seems to me that there are three fundamental problems with border-image:

  1. It conflates two orthogonal concepts: 9-slice scaling is useful for images in general, and using images for borders is useful with or without 9-slice scaling.
  2. It doesn’t play well with other properties, like border-radius. Presumably this was done because border-image was designed before @supports, so we probably thought border-radius and border can be used to provide a decent fallback?
  3. It doesn’t cover all relevant use cases

It’s probably not worth trying to reuse border-image for this, since border-image: <image> is valid syntax, it will impose severe restrictions in terms of what we can do. Perhaps border-layer could work (since we recently added background-layer) and naturally affords multiple images. We could even move the <image-1D> syntax to that, which currently awkwardly sits in border-color.

For 1, I think a good way forwards would be to offload the scaling logic to @image and have border-layer only deal with assigning one or more <image> values to border parts and doing reasonable things by default.

For 2, it seems obvious that whatever replaces it should naturally follow border-width, border-radius, border-style etc. it could also have corresponding side longhands for specifying separate images per border.

For 3, I think the main categories of use cases are, in order of less to more control:

  1. Entire image used in the border area (see use cases for [css-backgrounds] background-clip: border-area #9456)
  2. 9-slice scaling
  3. Separate images for sides/corners with auto-flip/rotate
  4. Separate images for sides/corners with no modification

One potential design, just to get the conversation started:

border-layer-source: <image>#
border-layer-align: [ auto | normal ]#;
border-layer: [<border-layer-source> && <border-layer-align>?]#

With potential border-<side>-layer / border-<corner>-layer shorthands for separate images per side/corner.

@bradkemper
Copy link
Contributor

It seems to me that there are two fundamental problems with border-image:

It conflates two orthogonal concepts: 9-slice scaling is useful for images in general, and using images for borders is useful with or without 9-slice scaling.
It doesn’t play well with other properties, like border-radius. Presumably this was done because border-image was designed before @supports, so we probably thought border-radius and border can be used to provide a decent fallback?
It doesn’t cover all relevant use cases

I see these more as border-image limitations than border-image problems. It was never intended for border-image to be more than a 9-slicer, similar in capabilities to what Android provided natively (I don't remember which came first). Naturally, IMO, there should be other ways to put images into borders that doesn't involve doing a 9 slice, and that should be with a separate property. I suspect the appetite to do so earlier was reduced due to border-image's lack of popularity.

WRT border-radius, fallback was part of the reasoning, but also there is the fact that the images would not be clipped by the border box. Even with overflow: hidden, clipping the border image would not be desirable, as the image is able to extend beyond those edges, and have any manner of shadows, glows, filigree, or whatever that was just ink. Most of the time, if you wanted round corners you'd just build them into the image. Border-radius is something that shapes a border, but only clips the background (or contents, with a non-visible overflow). I don't think there is any good way for border-radius to shape or clip border-image, and it isn't necessary if the image already describes the corners, but border-radius is good as a fallback.

@bradkemper
Copy link
Contributor

bradkemper commented Dec 16, 2023

Correct me if I'm wrong, but it sounds like your concept involves clipping the images in all cases to the shaped border area. I think that is the single biggest difference in concept between what your proposal does and what border-image does (at least with regard to the 9-slice part).

I think another use case, which might need a separate syntax, would be distributing and rotating one or more small images around the border. I see this as a sort of alternative to dotted or dashed borders, but using images. So maybe border-style: image-border(<image-source>, <image-size>, <space-length>). Maybe include something to say whether or not the images rotate, to be perpendicular or parallel (or not) to the center of the stroke. Maybe instead of <image-size>, it is just a length for the dimension not handled by border-width. Maybe there could even be some values to allow jitter in the placement of the image.

@SelenIT
Copy link
Collaborator

SelenIT commented Dec 17, 2023

I guess that the main confusion regarding existing border-image comes from the fact that its name, default values and many old web manuals suggest that it's firmly tied to the border area of the element. However, it seems better to think of it as a separate decorative layer, not limited by the element border edge and not strictly related to the box model of the element at all. It's its ability to paint things in the margin area of the element (and beyond) that I, for one, find the most useful (and exciting:), and many modern use cases seem to make use exactly of it (like full-bleed backgrounds with no extra markup, long shadows, or regular shadows with improved performance and behavior). Perhaps it would be better to rename it to something like edge-decoration instead of "killing with fire"? 😳

Also, the syntax of border-image is already reused in mask-border.

@SebastianZ
Copy link
Contributor

SebastianZ commented Dec 20, 2023

Overall border-image is a mess, and most authors won't touch it with a bargepole unless they really have to

I wouldn't go that far and say that it's a mess, though its handling around the 9-slice scaling is far from intuitive.

Fixing border-image

It seems to me that there are three fundamental problems with border-image:

  1. It conflates two orthogonal concepts: 9-slice scaling is useful for images in general, and using images for borders is useful with or without 9-slice scaling.

I don't believe 9-slice scaling is useful beyond border images. I'd even say it is not useful at all besides reducing network requests.

  1. It doesn’t play well with other properties, like border-radius. Presumably this was done because border-image was designed before @supports, so we probably thought border-radius and border can be used to provide a decent fallback?

Maybe someone can shed light on why this restriction actually exists.

It’s probably not worth trying to reuse border-image for this, since border-image: <image> is valid syntax, it will impose severe restrictions in terms of what we can do.

Like @bradkemper (and the people behind the issues linked to in the issue description) I tend to believe it is better to fix and improve border-image rather than getting rid of it.

Perhaps border-layer could work (since we recently added background-layer) and naturally affords multiple images.

That's something that should be pitched in #8802.

We could even move the <image-1D> syntax to that, which currently awkwardly sits in border-color.

I was also thinking of moving <image-1D> to the border images rather than border-color. Therefore, I've now created #9735.

For 3, I think the main categories of use cases are, in order of less to more control:

  1. Entire image used in the border area (see use cases for [css-backgrounds] background-clip: border-area #9456)

  2. 9-slice scaling

  3. Separate images for sides/corners with auto-flip/rotate

  4. Separate images for sides/corners with no modification

More generally, I'd say the use cases currently not covered by border-image are:

  1. Multiple images
  2. Positioning images within different parts of the border image area
  3. Border images being influenced by border-radius
  4. More control over image repetition

As a side note, mentally, I always separated borders from box decorations. Though I have to say, I like @SelenIT's suggestion to think of borders as a decorative layer. So maybe we could introduce something like box-decoration properties that cover more advanced use cases.

Sebastian

@SelenIT
Copy link
Collaborator

SelenIT commented Jan 3, 2024

Here is another creative effect that relies upon the border-image independence on border-radius as a feature: https://codepen.io/t_afif/pen/abMvjZj

@SelenIT
Copy link
Collaborator

SelenIT commented Jan 4, 2024

It seems to me that there are two main scenarios in which authors need to decorate borders with graphics, which I find significantly different conceptually:

  1. Take a specially designed predefined image and attach it to the box the way that serves the artistic intent the best;
  2. Take an existing border and fill it with the given graphical pattern, aligning this pattern with the border geometry where needed.

It looks that features that are good for the former ("image-first") class of use cases turn into downsides for the latter ("border-first"), and vice versa. The "image-first" approach needs as many levels of control that are resonably needed for artistic purposes, it shouldn'be limited with the edges of the border area, it may need handling different parts of the image independently, and so on. On the other hand, the "border-fist" approach needs to "automagically" know the exact geometry of the border area (including external/internal roundings and even fancier future corner shapes, perhaps even dashes/dots of respective border-styles) and ideally should "just work" with as few prerequisites as possible.

This conceptual difference seems so significant to me that I doubt that covering both scenarios with one tool is a good idea.

The existing border-image design seems good enough (not perfect, but perfection is unattainable) for the first scenario but hardly suitable at all for the second one. In other words, "border-image" turns out a rather poor choice for decorating borders with images, although a pretty good tool for visually enhancing boxes with non-trivial graphical effects. It's only connection to the actual border area is the default border-image-width:1, but it works for thick rectangular borders only and unlikely has any real-life usage besides border-image tutorials:)

All the above leads me to conclusion that introducing a brand new simple property for the "border-first" cases (something like border-fill maybe?) might actually be more productive than attempting to "fix" border-image (along with its mask-border counterpart) to suit better the cases it turns out (in retrospect) not designed for 😳

@bradkemper
Copy link
Contributor

Take a specially designed predefined image and attach it to the box the way that serves the artistic intent the best;
Take an existing border and fill it with the given graphical pattern, aligning this pattern with the border geometry where needed.

I think this is a pretty fair characterization. Here is an example that I mocked up in 2009 during the drafting of Backgrounds and Borders 3, which would fall into your "image first" category:

http://www.bradclicks.com/cssplay/border-image/Alladins_Lamp_2.png

Here is another example of how border-image and border-radius could complement each other, if WebKit behaved reasonably (there was no Blink back then):

http://www.bradclicks.com/cssplay/BorderImageAndRadius.html

Some other samples of things where border-image and border-radius could be used together for good effect:

http://www.bradclicks.com/cssplay/border-image/borders.png

http://www.bradclicks.com/cssplay/bones_border/bones-border.png

These wouldn't be possible if border-radius clipped the border image. In fact, I don't see how it could, unless it clipped everything outside the border-box.

@bradkemper
Copy link
Contributor

I mean, if you wanted to have the rounded corners solid fill box with the same geometry even if the image didn't load, or if you wanted to also use some separate background or backdrop or box-shadow on the border-box, or if you wanted the border-box to scroll, then the samples would work well by combining border-image and border-radius.

@jsnkuhn
Copy link

jsnkuhn commented May 18, 2024

Dropping in some examples of things I've run into lately that, at least, to me seem like the kind of border decorations that should be doable without a border-image-source download. It seems that the way folks are currently dealing with these things is using pseudo element(s) (or presentational divs) as a decoration layer on top of the background but below the text. It certainly would be nice to have a built in layer for this and not have to bother with the pseudo(s) set up.

FYI, I'm not entirely sure if the heading styling with the left and right side decoration is really within scope here but it's not really a background thing either. There isn't really a simple way that I'm aware of to handle this sort of thing.

https://nier.square-enix-games.com/en-us/

image

https://nierautomata.square-enix-games.com/switch/en-us/

image

image

@jsnkuhn
Copy link

jsnkuhn commented May 25, 2024

ran into another example in a discord question. Worth pointing out in this case that the element background would be rounded but the decoration layer would not. So the 2 layers would need to have some independence.

https://nucleoapp.com/

imagen

@jsnkuhn
Copy link

jsnkuhn commented Jun 25, 2024

Have noticed some folks lately talking about using border-image as a translucent overlay for background-image(s). This works well but breaks if border-radius is added.

border-image: fill 0 linear-gradient(#0003,#000);  

https://www.youtube.com/watch?v=NwnZU6mWJkk

While this is traditionally done with an extra background layer I wonder if a decoration layer might be a good home for this kind of thing to keep the overlay separate from the background/borders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants