Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertical list of elements, where each row shrinks its width to match the inner content

Tags:

html

css

flexbox

I want to create a vertical list, where each row shrinks its width to perfectly contain its inner content (versus the default div behavior of expanding its width to fill the container).

I'd like to do this with only one HTML element for each row (no extra wrapping divs).

The following code does exactly what I want, but it doesn't work in Safari (bug?).

.container {
  margin: 10px;
  border: 2px solid #999;
  padding: 5px;
  display: flex;
  flex-direction: column;
  width: 300px
}
.row-item {
  padding: 5px;
  margin: 5px;
  border: 1px solid green;
  /* this will shrink the width to the inner content
        in Chrome and Firefox, but not in Safari */
  margin-right: auto;
}
<div class='container'>
  <div class='row-item'>Item #1</div>
  <div class='row-item'>Another Item...</div>
  <div class='row-item'>Item No. 3</div>
</div>

Here is a codepen with the above code: http://codepen.io/anon/pen/woKYqx

I know that it is trivial to solve this problem by adding a wrapping div and then using display: inline-block on the inner element (or several other similar solutions).

However, it seems like it should be possible to solve this without adding extra HTML elements. It is a fairly simple layout.

Is there a cross-browser way to do this with a single HTML element for each row?

like image 634
Daniel Waltrip Avatar asked Nov 09 '16 23:11

Daniel Waltrip


2 Answers

You're using margin-right: auto to push the element all the way to the left, which also forces the item to take the width of its content.

This is a good method but, as you've noted, it fails in Safari.

A simple alternative is to use align-self: flex-start on the flex items:

.row-item {
  padding: 5px;
  margin: 5px;
  border: 1px solid green;
  align-self: flex-start;  /* NEW */
  /* margin-right: auto;  (can be kept or removed) */
}

OR, just use align-items: flex-start on the flex container.

.container {
  margin: 10px;
  border: 2px solid #999;
  padding: 5px;
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* NEW */
  width: 300px
}
like image 156
Michael Benjamin Avatar answered Oct 05 '22 13:10

Michael Benjamin


You can erase all flex stuff and use float:left and clear:left on the children, and overflow-x: hidden on the parent:

http://codepen.io/anon/pen/pNjQJJ

like image 25
Johannes Avatar answered Oct 05 '22 12:10

Johannes