14

In the example below I desire to get all items to be the width of largest content (e.g item 5).

  • The number of items in the list is dynamic and there could be hundred of them.

  • The width of each item content is also dynamic.

  • The number of items in each row would vary dependant on the width of the container.

DESIRED OUTPUT

enter image description here

Note: Media queries won't work for my scenario.


USING CSS FLEX

Flex is considered to be one dimensional. This means it can achieve the desired result on a single axis (row) unless the content is smaller than the available space.

Non wrapping example (Single row)

.container {
  display: flex;
}

.item {
  background: #58c;
  text-align: center;
  white-space: nowrap;
  margin: 0 10px 10px 0;
  flex: 1;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longer</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
</div>

Flex's flex-wrap attribute can be used to create a two dimensional layout. Again this works nice but requires a fixed width value in order to calculate each items width.

Wrapping example (Multiple rows)

.container {
  display: flex;
  flex-wrap:wrap;
}

.item {
  background: #58c;
  text-align: center;
  white-space: nowrap;
  margin: 0 10px 10px 0;
  flex: 0 1 100px;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longer</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

USING CSS GRID

For two dimensional design, CSS Grid is recommended but the example below is using a fixed width. It seems like min-content needs factoring in here, but how?

Failed example

grid-template-columns: repeat(auto-fit, min-content);

FIXED EXAMPLE (Multple rows)

.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, 100px);
  grid-auto-rows: 20px;
  grid-gap: 5px;
}

.item {
  background: #58c;
  text-align: center;
  white-space: nowrap;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longer</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

I do not think this is achievable with grid because of the following W3C note:

"Automatic repetitions (auto-fill or auto-fit) cannot be combined with intrinsic or flexible sizes."


Summary

Fundamentally I think there is no intrinsic way to do this with css.

To get the width of each item it needs to be:

  • predefined (fixed).
  • inferred horizontally using a percentage or fraction.
  • inferred vertically from the current column.

I see no way to infer an items width from another row AND column simultaneously.

DreamTeK
  • 32,537
  • 27
  • 112
  • 171
  • possible duplicate of : https://stackoverflow.com/questions/48003318/width-of-widest-element-sets-width-of-all-siblings-in-the-row/48007372#48007372 – Temani Afif Apr 30 '18 at 09:27
  • @TemaniAfif not exactly the same issue. I have ammended my question to clarify. – DreamTeK Apr 30 '18 at 10:14
  • I know, that's why i simply made it a possible duplcate and I didn't close it as it's a related question than can give you some ideas – Temani Afif Apr 30 '18 at 10:18
  • @TemaniAfif I thought it was the solution at first but my main issue here is having an unknown number of items. Any ideas? – DreamTeK Apr 30 '18 at 10:20
  • with pure CSS I have no idea for this, for one row layout it will be easy but for multiple row I don't know if we can do it – Temani Afif Apr 30 '18 at 10:22
  • 1
    @leonheess Not even close. All of the answers have a fixed html layout. It needed to be dynamic. – DreamTeK Aug 17 '21 at 08:00
  • 1
    @DreamTeK Thanks for the quick answer, I retracted my close-vote – leonheess Aug 17 '21 at 09:06

2 Answers2

1

This seems like a problem that CSS Grid should be able to handle. But I haven't seen anything in the spec that provides a solution. I'm not saying it's not there, either as one simple command or a combination of rules. I just haven't found it (if it exists).

Here's the closest I've been able to get:

.container {
  display: grid;
  grid-auto-columns: min-content; /* max-content works, as well */
  grid-gap: 10px;
}

.item {
  background: #58c;
  text-align: center;
  white-space: nowrap;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longer</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

The code above solves the width problem — all items are the length of the longest item. But there's no wrapping. The problem is flipped in the example below.

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min-content, 1px));
  grid-gap: 10px;
}

.item {
  background: #58c;
  text-align: center;
  white-space: nowrap;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longer</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

The code above gets the wrapping going, and gets around the intrinsic size limitation when using repeat(). However, the longest-content equal length requirement fails.

7.2.2.1. Syntax of repeat()

Automatic repetitions (auto-fill or auto-fit) cannot be combined with intrinsic or flexible sizes.

  • An intrinsic sizing function is min-content, max-content, auto, fit-content().

  • A flexible sizing function is <flex> (fr).

You can get around the auto limitation with something like this:

repeat(auto-fill, minmax(min-content, 1px))

minmax(min,max)

Defines a size range greater than or equal to min and less than or equal to max.

If max < min, then max is ignored and minmax(min,max) is treated as min.

As a maximum, a <flex> value sets the track’s flex factor; it is invalid as a minimum.

Maybe somebody else can take it from here.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 2
    @Micheal_B Thanks for the insight. This is pretty much where I got to and I read the entire spec yesterday. I thought it would be something simple but it seems unachievable with grid. – DreamTeK May 01 '18 at 07:24
-1

Look like without JS you can no not do this.

With JS you can calculate max width and set it to all elements.

After that display all child elements as inline-block inside block parent div.

<style>
    .container.init {
        display: inline-block;
        max-height: 100px;
        visibility: hidden;
    }
    .container .item {
        display: inline-block;
        background: #58c;
        text-align: center;
        white-space: nowrap;
        margin: 0 10px 10px 0;
    }
    .container.init .item {
        display: block;
    }
</style>
<div class="container init">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5 is longest text ever</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
</div>
<script>
    var max = document.querySelector('.container .item').offsetWidth;

    var styles = '.container .item { width: ' + max + 'px; }';

    var styleSheet = document.createElement("style");
    styleSheet.type = "text/css";
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);

    document.querySelector('.container.init').classList.remove('init');
</script>
Enyby
  • 4,162
  • 2
  • 33
  • 42
  • @DreamTeK The order of script execution in this case is important. What is lost after you have edited my code. People blindly copy the script code in the head and they will not work for them. – Enyby Apr 29 '20 at 21:33