I have n elements containing a small amount of text that I want to display in a fixed-width container as one row like so:
However, when all the inner text elements cannot fit in a single row, I want them appear in a single column:
I don't want to use inline-blocks so that there will be multiple rows, and a dynamic number of elements per row:
And I don't want the elements to be split across n columns depending on the size. It should be one row, or one column if that doesn't fit.
Can this be done with just CSS? Perhaps using flexbox or grid layout?
The display CSS property sets whether an element is treated as a block or inline element and the layout used for its children, such as flow layout, grid or flex. Formally, the display property sets an element's inner and outer display types.
The display property specifies the display behavior (the type of rendering box) of an element. In HTML, the default display property value is taken from the HTML specifications or from the browser/user default style sheet. The default value in XML is inline, including SVG elements.
The display property sets or returns the element's display type. Elements in HTML are mostly "inline" or "block" elements: An inline element has floating content on its left and right side. A block element fills the entire line, and nothing can be displayed on its left or right side.
I think this is not possible without JavaScript (because you need it to detect overflow). With that being said, you could base your solution around flexbox
as it allows you to switch between row / column layout via single CSS property on your container element. Other option might be to switch between inline-block
/ block
display on the children for example, but you would have to do that for all of them - that's why flexbox
is better here. Example might look like this:
const outer = document.querySelector('.outer')
if (outer.clientWidth < outer.scrollWidth) {
outer.classList.add('direction-column');
} else {
outer.classList.add('direction-row');
}
.outer {
background-color: lightgrey;
width: 500px;
padding: 10px;
display: flex;
align-items: flex-start;
}
.inner {
background-color: darkgrey;
margin: 5px;
flex: none;
}
.direction-row {
flex-direction: row;
}
.direction-column {
flex-direction: column;
}
<div class="outer">
<div class="inner">Some text, blah</div>
<div class="inner">Some text, blah blah</div>
<div class="inner">Some text, blah blah blah</div>
<div class="inner">Some text, blah blah blah blah</div>
<div class="inner">Some text, blah blah blah blah blah</div>
<div class="inner">Some text, blah blah blah blah blah blah</div>
</div>
I find this question interesting. One possible solution is using Media Query, but only if you know the exact width at which the .outer
container will break the layout of your .inner
classes. If the text won’t change dynamically, then you can easily calculate the width. In that case, you might use:
.inner {
display: inline-block;
}
@media only screen and (max-width: 877px) {
.inner {
display: block;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-size: 14px;
color: #222;
font-family: monospace;
}
.outer {
padding: 0 10px;
width: fit-content;
}
.inner {
width: auto;
height: auto;
margin: 10px 0;
background-color: darkgrey;
}
<div class="outer">
<p>
<span class="inner">blah blah</span>
<span class="inner">blah blah blah</span>
<span class="inner">blah blah blah blah</span>
<span class="inner">blah blah blah blah blah</span>
<span class="inner">blah blah blah blah blah blah</span>
</p>
</div>
It is an unusual workaround but it is CSS only.
As have already been said there is no CSS
method of detecting overflow.
Dynamic solution
So we can make texts container display: flex
with flex-wrap: wrap;
and with javascript
look on window resize if the last element offset
top
of text elements is bigger that first element's. And in this case modify texts container to flex-direction: column;
Look jquery
and javascript
versions in snippets in full page mode and resize the window.
Jquery version
$(function() {
detectWrap();
});
$(window).resize(function() {
detectWrap();
});
function detectWrap() {
$(".container").each(function() {
$(this).removeClass("direction-column");
if ($(this).children().first().offset().top < $(this).children().last().offset().top) {
$(this).addClass("direction-column");
}
});
}
.container {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
background-color: #D3D3D3;
padding: 10px;
margin: 10px 0;
}
.text-element {
background-color: #A9A9A9;
margin: 5px;
padding-bottom: 4px;
}
.direction-column {
flex-direction: column;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
Javascript version
window.onload = function(event) {
detectWrap();
};
window.onresize = function(event) {
detectWrap();
};
function detectWrap() {
const container = document.getElementsByClassName("container");
for (let i = 0; i < container.length; i++) {
container[i].classList.remove("direction-column");
const firstText = container[i].firstElementChild;
const lastText = container[i].lastElementChild;
if (firstText.offsetTop < lastText.offsetTop) {
container[i].classList.add("direction-column");
}
}
}
.container {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
background-color: #D3D3D3;
padding: 10px;
margin: 10px 0;
}
.text-element {
background-color: #A9A9A9;
margin: 5px;
padding-bottom: 4px;
}
.direction-column {
flex-direction: column;
}
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
<div class="container">
<div class="text-element">Some text, blah</div>
<div class="text-element">Some text, blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
<div class="text-element">Some text, blah blah blah</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With