Skip to content

[css-grid][css-flexbox][css-multicol] Styling Gaps/Gutters #2748

Closed

Description

@fantasai

There's been a number of requests for styling grid gaps (gutters). We have a column-rule property from the multicol module we should probably try to re-use, but the styling requirements for grids are more complicated due to e.g. spanning elements, which we have to figure out what to do with.

There's also styling requirements that apply to both multicol and grid that we aren't meeting. (E.g. having the rule start not flush with the top/bottom of the column boxes but somewhat inset, various fancier graphical effects than a simple “line”.)

Basic line rules that can reasonably interact with spanning elements is the top priority, but we should have some idea at what else we might need to accommodate in the future.

This is a placeholder issue to collect use cases and examples, so that we understand problems we need to handle before we try to design a solution. Please add suggestions/examples/ideas/drawings/background info/warnings/suggestions/anything else that seems like it might be helpful! While we're unlikely to handle 100% of all the graphic design capabilities the Internet can imagine, we should at least aim to handle the more common cases.

Activity

  1. tsiq-swyx commented on Jun 8, 2018

    @tsiq-swyx

    Just adding a couple common questions and our twitter discussion:

    my use case - if i were to make this table and didnt want to use border-bottom or add (a few) extra 1px elements:

    image

    grid-row-gap-color: gray might do it? i am definitely not the guy to ask about coming up with css specs haha

    I understand the conflict between columns and rows, but i would only use one or the other myself.

    another way to do it would be to style between named or numbered line markers.

    i love that you are still willing to consider this, please keep it up!

  2. fantasai commented on Jun 8, 2018

    @fantasai
    CollaboratorAuthor

    @tsiq-swyx If you were to make that table, please, please use <table> markup? :) Data tables should be marked up with data table markup.

  3. watershed commented on Dec 11, 2018

    @watershed

    Hi. Rachel Andrew kindly let me know about this open issue. I've put a Pen together which I hope is a relevant use case: Horizontal lines between CSS grid rows.

  4. SebastianZ commented on Dec 12, 2018

    @SebastianZ
    Contributor

    I believe allowing images of some form within the line gaps together with some way to inset them would cover all use cases.

    Also, the name should be general enough to also cover horizontal rules. So it may be aligned to the gap property.

    So, one approach extending column-rules syntax could be

    gap-rule: [ <'gap-rule-width'> <'gap-rule-length'>? ] || [ [ <'gap-rule-style'> ||
        <'gap-rule-color'> ] | [ <'gap-rule-image'> ] ]
    

    with gap-rule-width being an extended version of <line-width>

    gap-rule-width = <length-percentage> | thin | medium | thick
    

    where the percentage refers to the width of the gutter.

    gap-rule-length would be used for insetting (or outsetting) the rule in the orthogonal direction to gap-rule-width with an initial value of 100%

    gap-rule-length = <length-percentage>
    

    where the percentage refers to the length of the gutter.

    gap-rule-style = <line-style>
    gap-rule-color = <color>
    

    being the equivalents for column-rule-style and column-rule-color.

    And the gap-rule-image would be defined as

    gap-rule-image = <image> [ stretch | repeat | round | space ]{1,2}
    

    where the repetition values work like for border-image-repeat.

    The rule is always centered horizontally and vertically within the gutter.

    Examples:

    gap-rule: 1px solid silver; /* equal to the existing column-rule: 1px solid silver; */
    gap-rule: 2px 80% dotted blue; /* draws a 2px wide blue dotted line spanning 80% of the length of the gutter */
    gap-rule: 10px calc(100% - 20px) url(rule.svg) /* draws a 10px wide and 10px inset stretched image */
    

    Regarding spanning elements and gutter intersections, there may be another property specifying whether the rules cross the elements or each other or are interrupted. E.g. something like

    gap-rule-interrupt: [ continuous | interrupt ]{1, 2}
    

    allowing to control the horizontal and vertical interruption individually.

    Examples:

    gap-rule-interrupt: continuous; /* draws the rule(s) without interruption by spanning elements or crossing rules */
    gap-rule-interrupt: interrupt continuous; /* draws the rule(s) with interruption in vertical direction but not in horizontal direction */
    

    I'll try to come up with some visual representations of the examples above.

    Sebastian

  5. SebastianZ commented on Dec 12, 2018

    @SebastianZ
    Contributor

    Here are the examples including their output:

    gap-rule: 1px solid silver;
    

    Example for gap-rule: 1px solid silver;

    gap-rule: 2px 80% dotted blue;
    

    Example for gap-rule: 2px 80% dotted blue;

    gap-rule: 10px calc(100% - 20px) url(rule.svg)
    

    Example for gap-rule: 10px calc(100% - 20px) url(rule.svg)

    gap-rule-interrupt: continuous;
    

    Example for gap-rule-interrupt: continuous;

    gap-rule-interrupt: interrupt continuous;
    

    Example for gap-rule-interrupt: interrupt continuous;

    Sebastian

  6. watershed commented on Dec 13, 2018

    @watershed

    Good stuff Sebastian.

    My only observation is that because grid-gap specifies the row gap first and the column gap optionally second, it is a bit odd for a property such as gap-rule-interrupt to do the inverse: specify the column interrupt first and the row interrupt second.

    There should be a consistent pattern.

  7. SebastianZ commented on Dec 27, 2018

    @SebastianZ
    Contributor

    @watershed Right, gap-rule-interrupt should follow the gap syntax, so first the row then the column.

    Also, gap-rule-interrupt may be included in the gap-rule shorthand, so the syntax for it would then be like this:

    gap-rule: [ <'gap-rule-width'> <'gap-rule-length'>? ] || [ [ <'gap-rule-style'> ||
    <'gap-rule-color'> ] | [ <'gap-rule-image'> ] ] || <'gap-rule-interrupt'>{1,2}
    

    So the full value to get the last example would be:

    gap-rule: 1px solid silver continuous interrupt;
    

    To allow to set the vertical and horizontal rules individually, the gap-rule property could also be split up into row-gap-rule and column-gap-rule.

    Sebastian

  8. SebastianZ commented on Sep 22, 2019

    @SebastianZ
    Contributor

    @fantasai Are there more use cases needed or anything else to push this forward?

    Sebastian

  9. SebastianZ commented on Oct 19, 2019

    @SebastianZ
    Contributor

    It wasn't explicitly mentioned yet, but styling gaps should also apply to Flexbox layouts.

    Sebastian

  10. BlueskyFR commented on Nov 17, 2019

    @BlueskyFR

    Hello,
    This is my first post here.
    What if it was instead possible to add more options to the current grid-gap property while including @SebastianZ's idea?
    Like grid-gap: 10px, grid-gap: 10px 20px, grid-gap: 10px solid black, grid-gap: 10px 20px solid black, grid-gap: 10px 20px url(image.png), grid-gap: 10px 20px solid red solid black continuous interrupt.

    What do you think ?

  11. SebastianZ commented on Nov 18, 2019

    @SebastianZ
    Contributor

    Note that grid-gap got renamed to just gap (and also grid-row-gap and grid-column-gap to row-gap and column-gap) in order to be also used in flexbox and multi-column layout.

    The rule styles might be applied directly in the gap property but this also brings some disadvantages. First, it would make the lengths ambiguous, because it mixes the sizes of the gaps with the width and length of the rule. Second, it requires you to always define both when you only want to overwrite one of them.

    Sebastian

  12. BlueskyFR commented on Nov 18, 2019

    @BlueskyFR

    How is it possible to rename a css property?
    I mean, this will make incompatible many websites.

  13. SebastianZ commented on Nov 18, 2019

    @SebastianZ
    Contributor

    Having a look at the syntax of my last comment from December 2018, I realized that it missed the optional second interruption value. Therefore I've now added a {1,2} behind it.

    Sebastian

  14. 22 remaining items

  15. css-meeting-bot commented on May 6, 2020

    @css-meeting-bot
    Member

    The CSS Working Group just discussed Styling gap.

    The full IRC log of that discussion <fremy> Topic: Styling gap
    <astearns> github: https://github.com//issues/2748
    <fremy> fantasai: this seems to be a feature that people really want to have
    <fremy> fantasai: and we don't really offer any affordance for that
    <fremy> fantasai: one open issue, is what happens in a grid when an item spans accross a gap
    <fremy> fantasai: should the gap break over this item or not
    <fremy> fantasai: but I am concerned that having this kind of stylistic feature should best be done in a real f2f because we need to whiteboard
    <fremy> astearns: any other opinion?
    <fremy> rachelandrew: more than rows and columns
    <fremy> rachelandrew: I have had many requests for borders around grid areas
    <fremy> iank_: also, we get into issues similar to tables
    <fremy> iank_: what happens at intersections, when the borders are not the same
    <fremy> astearns: I think we should not mix those two things up
    <fremy> astearns: styling gaps sounds easier
    <fremy> astearns: styling areas is more complex, and might need more work
    <fremy> astearns: could be done later
    <fremy> jensimmons: I agree with astearns here
    <fremy> jensimmons: and it's a feature that makes a lot of sense to do from a design point of view
    <fremy> jensimmons: and getting half of what authors want is still great progress
    <fremy> rachelandrew: the issue about spanning also applies to multi-columns as well
    <fremy> rachelandrew: because we can also span things in multi-columns
    <fremy> rachelandrew: so authors will want to "exclude" areas from the lines
    <fremy> rachelandrew: so it's not clear to me that ignoring areas entirely is fully possible/desirable
    <fremy> florian: if you have an area going through, don't you always want to break the rule?
    <fremy> iank_: not always, the thing in the area can have a transparency background effect
    <fremy> miriam: what does happen in multicol now?
    <fremy> rachelandrew/florian: it's interrupted
    <fremy> astearns: based on all these comments, I think it would indeed be nice to have a whiteboard
    <fremy> astearns: so I propose to move back to the github issue as a proxy-whiteboard
    <fremy> astearns: any other comment?
  16. MatsPalmgren commented on May 18, 2020

    @MatsPalmgren

    FYI, I've made a proposal to add image support for column rules in #5080.

  17. fantasai commented on Oct 1, 2021

    @fantasai
    CollaboratorAuthor

    Using Sebastian Zartner's diagrams of grid line intersection options in #5080, @mirisuzanne and I sketched out the following syntax proposal to handle segmenting:

    column-rule-extent: span-skip | no-skip | span-break | corner-break
    

    column-rule-extent specifies how column rules are segmented. Each segment is drawn separately, and has its own inset and image application, if any.

    • no-skip - extends across the grid, going behind grid items
    • span-skip - extends across the grid, not drawn behind grid items
    • span-break - spanning items split rule into individual segments
    • corner-break - split at every intersection

    Note: In Flexbox, the cross-axis rules are always segmented between flex lines.

    We thought it made more sense to split out handling of whether lines cross the gaps into a separate property, maybe the column-rule-inset property @MatsPalmgren mentioned earlier:

    column-rule-inset: nearest | center | farthest | <length>
    

    column-rule-inset specifies how far a column rule extends into (or recedes from) an intersecting gap (or the edge of the container).

    • nearest - Segment not extend into the gap. Computes to zero.
    • center - Segment extends to the center of the gap.
    • farthest - Segment crosses the entire gap.
    • <length> - Segment intrudes by given length.

    (At the edge of a container, where there is no gap, a gap is assumed to exist for the purpose of calculating the rule's length. This ensures symmetry.)

    The keywords might need some bikeshedding. And/or we might want rule-outset instead of rule-inset.

    Putting it all together, we'd have the following syntaxes for gap styling (with row-/column-/unprefixed variants for each):

    /* Existing Properties */
    column-gap: normal | <length-percentage>
    column-rule: <color> || <line-style> || <line-width>
      column-rule-color: <color>
      column-rule-style: <line-style>
      column-rule-width: <line-width>
    
    /* Proposed Properties */
    column-rule-extent: span-skip | no-skip | span-break | corner-break
    column-rule-inset: nearest | center | farthest | <length>
    column-rule-image: <border image syntax but with only one axis>
      rule-image-source: none | <image>
      rule-image-slice: [ <number [0,∞]> | <percentage [0,∞]> ]{1,2}
      rule-image-width: [ <length-percentage [0,∞]> | <number [0,∞]> | auto ]
      rule-image-outset: [ <length [0,∞]> | <number [0,∞]> ]{1,2}
      rule-image-repeat: [ stretch | repeat | round | space ]
    

    (See also open questions in @SebastianZ's post, which are follow-up questions we'll need to answer.)

    What do people think?

  18. SebastianZ commented on Nov 1, 2021

    @SebastianZ
    Contributor

    @fantasai @mirisuzanne I gave your suggested syntax some thought now and have some remarks and questions.

    1. The wording of your proposal seems to exclude multi-column containers. Though I guess it would work the same there, right?
    2. What's the use case for column-rule-extent: no-skip? Implementation-wise it shouldn't be much different from span-skip, I presume, though I wonder if it's actually needed as a separate value.
    3. How do column-rule-extent and column-rule-inset work together? Are they completely separate from each other or does column-rule-inset require individual segments, i.e. column-rule-extent to be span-break or corner-break?
    4. As far as I understand it, column-rule-inset: farthest means that segments overlap each other, one ending at the gap end, one starting at the gap start. What's the use case for that?
    5. It's not explicitly mentioned, though I assume lengths in column-rule-inset can be negative to recede from the gap, right?
    6. I assume, authors may want to control the inset/outset at the container edge individually from the ones within the container to achieve effects like in my last mockup.
    7. How is rule-image-outset meant to work?
    8. You didn't mention it, though you probably meant to introduce the same properties for row rules, right?
    9. How do the proposed properties interact with the existing ones?

    Sebastian

  19. jonathandewitt-dev commented on Oct 7, 2022

    @jonathandewitt-dev

    Forgive me for coming into this discussion in the middle, I'll more thoroughly read all the replies a little later when I have more time.

    Am I right in assuming this is intended to draw a line between gaps, but not apply to the gaps themselves?

    I'm coming here from this discussion where I proposed a gap-fill property, before I was made aware of this issue and gap decorations in general. If I'm understanding @Loirooriol correctly, the idea to apply a background color to gaps overlaps with the goals of this proposal.

    My question is, would it be useful to apply a background to the gap and treat the *-rule properties as the foreground?

  20. tabatkins commented on Apr 27, 2023

    @tabatkins
    Member

    -extent and -inset are good; I think it fills the functionality fully. I'd probably fiddle with the names a bit, but that's it.

    The model, essentially, is that anything with gaps defines a collection of horizontal and/or vertical areas, plus intersection rects where they touch. The existing -rule properties define whether rules exist in the horiz/vert areas. At each intersection rect, a rule either stops (a break) or continues thru it to join with the rule on the other side; this is controlled by -extent. Depending on the -rule and -extent properties, an intersection rect might contain none, one, or two (intersecting) rules.

    -inset only controls rule breaks; by default the break is right up against the edge of the intersection rect, but you can shift it in or out.


    Hm, I do have a question about span-skip interactions, tho. Say you have a grid set up like:

    A│   │C
    ─╯   │C
         │C
    ─╮   │C
    B│   │C
    

    Assuming rules are drawn in both axises:

    -extent: corner-break

    A│ ┃ │C
    ─╯ ╹ │C
    ━╸   │C
    ─╮ ╻ │C
    B│ ┃ │C
    

    -extent: span-break

    A│ ┃ │C
    ─╯ ┃ │C
    ━╸ ┃ │C
    ─╮ ┃ │C
    B│ ┃ │C
    

    -extent: span-skip

    A│ ┃ │C
    ─╯ ┃ │C
    ━━━┫ │C
    ─╮ ┃ │C
    B│ ┃ │C
    

    -extent: no-skip

    A│ ┃ │C
    ─╯ ┃ │C
    ━━━╋━│C
    ─╮ ┃ │C
    B│ ┃ │C
    

    Right?

    The question is - what does span-skip look like if only row-gaps are drawn? How far into the intersection area does it extend?

    None?

    A│   │C
    ─╯   │C
    ━╸   │C
    ─╮   │C
    B│   │C
    

    Half?

    A│   │C
    ─╯   │C
    ━━━╸ │C
    ─╮   │C
    B│   │C
    

    All the way?

    A│   │C
    ─╯   │C
    ━━━━━│C
    ─╮   │C
    B│   │C
    

    Or should we implicitly treat this like a break, and let -inset take control?

    (Note that this will have an effect on how we want to handle gap images; see my comment on 5080 about handling intersections better. Under the model I describe there, the choice I'm outlining here is between using mid+endcap for this intersection area, or using a 1-way intersection for it.)

  21. samuelbradshaw commented on Oct 16, 2023

    @samuelbradshaw

    My use case for this is a left-and-right view in landscape that becomes a top-and-bottom view in portrait – with a divider in the middle (think split screen on a phone). Currently I have to use border-right in landscape, and switch to border-bottom in portrait. I would prefer setting a gap rule so the line automatically adjusts depending on the flex-direction.

        <style>
          #container {
            position: absolute;
            top: 0; bottom: 0; left: 0; right: 0;
            display: flex;
          }
          .synced-panel {
            overflow: scroll;
            padding: 2em;
            flex-basis: 100%;
          }
          .synced-panel:not(:last-of-type) { border-right: 2px solid #eee; }
          @media screen and (orientation: portrait) {
            #container { flex-direction: column; }
            .synced-panel:not(:last-of-type) { border-right: 0; }
            .synced-panel:not(:last-of-type) { border-bottom: 2px solid #eee; }
          }
        </style>
    
    Screenshot 2023-10-16 at 4 33 12 PM Screenshot 2023-10-16 at 4 33 19 PM
  22. kbabbitt commented on Jun 30, 2026

    @kbabbitt
    Collaborator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions