CSS dynamically determine number of columns based on max-content of children - css

I'm trying to use css columns to display a dynamic number of columns based on the maximum width needed for the children to display nicely (such that the text doesn't wrap onto a new line where possible). I'd then like to stretch each element to fit the available space in the column.
This is what I have (Here is a JSFiddle):
But this is what I'd like to see (all elements have equal width):
This is the code I've tried:
<div class="columns">
<div>
Lorem
</div>
<div>
Ipsum
</div>
<div>
Dollar
</div>
<div>
Euro
</div>
<div>
Bitcoin
</div>
</div>
* {
padding: 0;
margin: 0;
}
.columns {
columns: auto;
column-gap: 1rem;
background: #4cafff;
padding: 1rem 0;
}
.columns > div {
width: max-content;
background: #4caf50;
color: white;
font-size: 2rem;
border: 2px solid green;
margin: 1rem;
}

max-content is not work like that. It is make the content not to wrap. I mean, width or height of content will be maximum size of your content. It will be fit.
If you want to equal width of all element, you can use specific pixel for width.
Like this:
.columns > div {
width: 95px;
text-align: center;
background: #4caf50;
color: white;
font-size: 2rem;
border: 2px solid green;
margin: 1rem;
}

Try this CSS
* {
padding: 0;
margin: 0;
}
.columns {
display: flex;
flex-wrap: wrap;
background: #4cafff;
padding: 1rem 0;
}
.columns > div {
background: #4caf50;
flex: 1;
color: white;
font-size: 2rem;
border: 2px solid green;
margin: 1rem;
}

Related

How to remove this gap or merge the borders? Because the lengths are inconsistent

How to remove this gap or merge the borders? Because the lengths are inconsistent
box1 and box2 are 100px, box3 is 200px but their lengths are inconsistent because border...
so how do their length are consistent?
<main>
<div class="shortBox">box1</div>
<div class="shortBox">box2</div>
<div class="longBox">box3</div>
</main>
.shortBox {
width: 100px;
display: inline-block;
}
.longBox {
width: 200px;
}
.shortBox,
.longBox {
text-align: center;
font-size: 20px;
height: 50px;
background-color: #000;
color: #fff;
border: 1px solid #fff;
}
This happens when you have elements that have display: inline or inline-block. Since the browser treats these elements the same way as text, a line-break will be treated as white-space.
Setting the font size to 0 for the wrapper basically eliminates the whitespace, but keep in mind, that this property will be inherited to child elements, so you may have to set the font-size back to >0 for children. Also, this may break layouts that use em as unit, so keep that in mind. By also adding box-sizing: border-box the gaps are gone.
main {
font-size: 0;
}
.shortBox {
width: 100px;
display: inline-block;
}
.longBox {
width: 200px;
}
.shortBox,
.longBox {
box-sizing: border-box;
text-align: center;
font-size: 20px;
height: 50px;
background-color: #000;
color: #fff;
border: 1px solid #fff;
}
<main>
<div class="shortBox">box1</div>
<div class="shortBox">box2</div>
<div class="longBox">box3</div>
</main>
There is also a possible way to use comments to prevent the auto-formatting from adding the white-space / line-break. It does not look too elegant, but it gets the job done. Also, except for the box-sizing: border-box you don't need any additional CSS for this.
.shortBox {
width: 100px;
display: inline-block;
}
.longBox {
width: 200px;
}
.shortBox,
.longBox {
box-sizing: border-box;
text-align: center;
font-size: 20px;
height: 50px;
background-color: #000;
color: #fff;
border: 1px solid #fff;
}
<main>
<div class="shortBox">box1</div><!--
--><div class="shortBox">box2</div><!--
--><div class="longBox">box3</div>
</main>
The third way of solving this issue is to utilize flexbox. You can create layouts like this, without having to worry about gaps because of white-spaces or line-breaks.
watch this magic:
<main>
<div class="shortBox">box1</div><div class="shortBox">box2</div>
<div class="longBox">box3</div>
</main>
Notice that first 2 divs are NOT divided with new line.
Then in CSS add this extra 2px like this:
.longBox {
width: 202px;
}

Need all elements in a row to be the length of the longest sibling

I have some dynamically generated buttons, the button text may be a single word, or a small sentence. So I need the buttons to autosize to their content (i.e. can't use a fixed width).
But I also need all the buttons to be the same size, based on the size of the largest button. I know I can do this in JavaScript quite easily. I've provided an example of that below so you can see the expected result.
But I wondered if there was a way to do it just using CSS?
// Quick and dirty just for example purposes
document.addEventListener("DOMContentLoaded", function(event) {
var buttons = document.querySelectorAll('.container_two > button'),
biggest = {w:0, h:0};
buttons.forEach((btn) => {
var size = btn.getBoundingClientRect();
biggest.w = biggest.w < size.width ? size.width : biggest.w;
biggest.h = biggest.h < size.height ? size.height : biggest.h;
});
//console.log(biggest);
buttons.forEach((btn) => {
btn.style.width = Math.ceil(biggest.w)+'px';
// btn.style.height = biggest.h+'px'; -- flexbox will do this for us
});
});
strong { display: block; text-align:center;margin-bottom:1em; font-size: 20px; }
hr { margin: 1.5em 0 1em; }
button {
background: black;
color: white;
font-size: 16px;
padding: 0.5em 1em;
outline: none;
border-width: 0;
border-radius: 0.5em;
}
.container {
display: flex;
justify-content: center;
gap: 1em;
}
<strong>Original</strong>
<div class="container container_one">
<button>?</button>
<button>Yep sure, why not do it later?</button>
<button>Somewhere<br />over<br />the<br />rainbow</button>
</div>
<hr />
<strong>Javascript Solution</strong>
<div class="container container_two">
<button>?</button>
<button>Yep sure, why not do it later?</button>
<button>Somewhere<br />over<br />the<br />rainbow</button>
</div>
Try this:
Set the width of the container to shrink wrap the content (width: fit-content)
Use grid properties to distribute container space equally, which will set all buttons to the width of the longest element. (grid-template-columns: repeat(3, 1fr) or 1fr 1fr 1fr).
.container {
display: grid;
width: fit-content;
grid-template-columns: 1fr 1fr 1fr;
gap: 1em;
margin: 0 auto;
}
button {
background: black;
color: white;
font-size: 16px;
outline: none;
border-width: 0;
border-radius: 0.5em;
}
<div class="container">
<button>?</button>
<button>Yep sure, why not do it later?</button>
<button>Somewhere<br />over<br />the<br />rainbow</button>
</div>
Tested in Chrome, Firefox and Edge. Check fit-content in caniuse.com for full compatibility data.
I would recommend using flex-grow, just add it to the button and all buttons will grow to the same ratio if you make the ratio the same:
strong {
display: block;
text-align:center;
margin-bottom:1em;
font-size: 20px;
}
button {
background: black;
color: white;
font-size: 16px;
flex: 1; /* you can also use flex-grow: 1; */
padding: 0.5em 1em;
outline: none;
border-width: 0;
border-radius: 0.5em;
}
.container {
display: flex;
justify-content: center;
gap: 1em;
max-width: 813px;
margin: 0 auto;
/* change the width of the container in order to not fill the entire screen and keep to the required size */
}
<strong>Original</strong>
<div class="container container_one">
<button>?</button>
<button>Yep sure, why not do it later?</button>
<button>Somewhere<br />over<br />the<br />rainbow</button>
</div>

text background new line padding issue

I am dealing with text blocks (background blocks over text) and face some issues with paddings on new line. The problem occurs when the browser(e.g. mobile) cuts the text into to two lines due to lack of width. text then looks like this:
I don't really know how to set a padding css on the end of the new lines, since it could break up anywhere of the sentence. You could say put a span on it with padding, but it is not fixed where the line will break down. It depends on the width. Any recommendations?
You could apply display: inline-block but that will turn the background color into an ugly box which doesn't look as nice as having an exact width background for each line. Unfortunately CSS doesn't let us target individual lines except for the first one.
If you don't mind getting a little "creative" (or hacky) you could wrap each word in its own element in the backend or using JavaScript and apply the background color to those elements. Adjust the parent's word-spacing accordingly to eliminate gaps.
.main {
font-family: sans-serif;
font-weight: bold;
background-color: #99c;
display: flex;
height: 400px;
flex-direction: row;
align-items: center;
}
.text-container {
max-width: 500px;
display: inline-block;
word-spacing: -15px;
position: relative;
padding-left: 20px;
overflow: hidden;
}
.text-container::before {
content: '';
background-color: black;
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 100%;
z-index: 1;
}
span {
font-size: 36px;
line-height: 1.5em;
color: white;
background-color: black;
padding: 0.25em 0.5em 0.25em 0;
max-width: 360px;
}
<div class="main">
<div class="text-container">
<span>A</span> <span>Movie</span> <span>in</span> <span>the</span> <span>park:</span> <span>Kung</span> <span>Fu</span> <span>Panda</span>
</div>
</div>
You can use box-shadow for this issue and display inline:
<div class="text">
<span class="text-container">A Movie in the park: Kung Fu Panda</span>
</div>
And css:
.text > span {
display: inline;
box-shadow: 25px 0 0 black, -10px 0 0 black;
background-color: black;
color: white;
}
Try to add after "Park:" and before "Kung"
padding workded!!!
change width by console browser and see result:
h1{
background-color: #ff6a6a;
padding: 33px;
display: inline-block;
word-wrap: break-word;
width:300px
}
<h1>rert ert erttttttttttttttt 00000000000000000000 dfgdfgd dfgdfgdft ertert </h1>
Use <p> tag to wrap up the text and it apparently works demo
<div class="main">
<div class="text-container">
<p id="test">A Movie in the park: Kung Fu Panda</p>
</div>
</div>
css
.main {
font-family: sans-serif;
font-weight: bold;
background-color: #99c;
display: flex;
height: 400px;
flex-direction: row;
align-items: center;
}
.text-container {
max-width: 400px;
}
p {
font-size: 36px;
line-height: 2em;
color: white;
background-color: black;
padding: 0.5em;
max-width: 360px;
}

How do I evenly distribute a group of spans across a div?

I have an aside on the side of my webpage that contains span blocks that contain tags for blog posts. Right now, they're set up with display: inline-table that put multiple on each line and then go to the next line as overflow.
If possible (and JavaScript is okay, but CSS is preferred), how can I get these spans to take up the entire width inside of the div so I don't have the "rough edge" to the right? I'd like to either increase the margins between the span blocks or I'd be okay with increasing the width of the span as well.
Here's the code I currently have:
body {
background-color: #333;
color: #333332;
}
aside {
background-color: white;
width: 300px;
height: 300px;
margin: auto;
}
h2 {
margin: 24px;
padding-top: 24px;
}
.tag-wrapper {
padding: 0px 24px;
}
span {
display: inline-table;
text-transform: uppercase;
background-color: #F77C2F;
margin: 4px 2px;
padding: 8px;
}
<div class="container">
<aside>
<h2>Tags</h2>
<div class="tag-wrapper">
<span>finance</span>
<span>if</span>
<span>pv</span>
<span>pivot tables</span>
<span>vba</span>
<span>test</span>
<span>test</span>
<span>test</span>
</div>
</aside>
</div>
A little flexbox magic will get the job done:
body {
background-color: #333;
color: #333332;
}
aside {
background-color: white;
width: 300px;
height: 300px;
margin: auto;
}
h2 {
margin: 24px;
padding-top: 24px;
}
.tag-wrapper {
padding: 0px 24px;
display: flex;
flex-flow: row wrap;
align-content: stretch;
}
span {
flex: 1 0 auto;
text-transform: uppercase;
background-color: #F77C2F;
margin: 4px 2px;
padding: 8px;
}
<div class="container">
<aside>
<h2>Tags</h2>
<div class="tag-wrapper">
<span>finance</span>
<span>if</span>
<span>pv</span>
<span>pivot tables</span>
<span>vba</span>
<span>test</span>
<span>test</span>
<span>test</span>
</div>
</aside>
</div>
The properties used are:
display: flex: this sets the display type of the container to flex (aka flexbox)
flex-flow: row wrap: makes items order in a row, and wrap as required.
align-content: stretch: makes items stretch to fill the flex direction (row).
flex 1 0 auto: makes the items "growable" (1), but not "shrinkable" (0), and use self base width (auto) before distributing leftover space.
Is this what you are talking about? If so, just change the display of the span to block instead of inline-block.
body {
background-color: #333;
color: #333332;
}
aside {
background-color: white;
width: 300px;
height: 300px;
margin: auto;
}
h2 {
margin: 24px;
padding-top: 24px;
}
.tag-wrapper {
padding: 0px 24px;
}
span {
display: block;
text-transform: uppercase;
background-color: #F77C2F;
margin: 4px 2px;
padding: 8px;
}
<div class="container">
<aside>
<h2>Tags</h2>
<div class="tag-wrapper">
<span>finance</span>
<span>if</span>
<span>pv</span>
<span>pivot tables</span>
<span>vba</span>
<span>test</span>
<span>test</span>
<span>test</span>
</div>
</aside>
</div>

Create line after text with css

Im trying to make a line after each of my h2 tags. I canĀ“t figure out how I should tell the width, cause the lenght of the h2 headlines is differ from h2 to h2.
I use the :after method to create lines
h2:after {
position: absolute;
content: "";
height: 2px;
background-color: #242424;
width: 50%;
margin-left: 15px;
top: 50%;
}
Check code here: http://jsfiddle.net/s9gHf/
As you can see the line get too wide, and make the website too wide.
You could achieve this with an extra <span>:
h2 {
font-size: 1rem;
position: relative;
}
h2 span {
background-color: white;
padding-right: 10px;
}
h2:after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 0.5em;
border-top: 1px solid black;
z-index: -1;
}
<h2><span>Featured products</span></h2>
<h2><span>Here is a very long h2, and as you can see the line get too wide</span></h2>
Another solution without the extra <span> but requires an overflow: hidden on the <h2>:
h2 {
font-size: 1rem;
overflow: hidden;
}
h2:after {
content: "";
display: inline-block;
height: 0.5em;
vertical-align: bottom;
width: 100%;
margin-right: -100%;
margin-left: 10px;
border-top: 1px solid black;
}
<h2><span>Featured products</span></h2>
<h2><span>Here is a very long h2, and as you can see the line get too wide</span></h2>
External examples: First, Second
There's no need for extra wrappers or span elements anymore. Flexbox and Grid can handle this easily.
h2 {
display: flex;
align-items: center;
}
h2::after {
content: '';
flex: 1;
margin-left: 1rem;
height: 1px;
background-color: #000;
}
<h2>Heading</h2>
using flexbox:
h2 {
display: flex;
align-items: center;
}
h2 span {
content: "";
flex: 1 1 auto;
border-top: 1px solid #000;
}
<h2>Title <span></span></h2>
Here is another, in my opinion even simpler solution using a flex wrapper:
.wrapper {
display: flex;
align-items: center;
}
.line {
border-top: 1px solid grey;
flex-grow: 1;
margin: 0 10px;
}
<div class="wrapper">
<p>Text</p>
<div class="line"></div>
</div>
External link
I notice that there are some flexbox implementations but they don't explain why and how to use it.
First, we just need one element, for this example h2.
We will change the element's display behavior to display: flex
Then, we center vertically its child elements using align-items: center.
h2 {
...
display: flex;
align-items: center;
}
Then, let's draw the line using the pseudo-element after.
We add '' to the content property to draw the element (we must).
Now lets make it flexible using flex: auto. This means that our element is sized according to its width and height properties. It grows to absorb any extra free space in the flex container, and shrinks to its minimum size to fit the container. This is equivalent to setting flex: 1 1 auto.
Then we add an small gap between the text and the line using margin-left: 1rem.
Finally, we draw a black line using border-top: 1px solid #000.
h2::after {
content: '';
flex: auto;
margin-left: 1rem;
border-top: 1px solid #000;
}
Here is functional snippet.
h2 {
font-size: 1em; /* not needed */
display: flex;
align-items: center;
}
h2::after {
content: '';
flex: auto;
margin-left: 1rem;
border-top: 1px solid #000;
}
<h2>Normal title</h2>
<h2>Very long title to test the behavior of the element when the content is wider</h2>
This is the most easy way I found to achieve the result: Just use hr tag before the text, and set the margin top for text. Very short and easy to understand! jsfiddle
h2 {
background-color: #ffffff;
margin-top: -22px;
width: 25%;
}
hr {
border: 1px solid #e9a216;
}
<br>
<hr>
<h2>ABOUT US</h2>
Here is how I do this:
http://jsfiddle.net/Zz7Wq/2/
I use a background instead of after and use my H1 or H2 to cover the background. Not quite your method above but does work well for me.
CSS
.title-box { background: #fff url('images/bar-orange.jpg') repeat-x left; text-align: left; margin-bottom: 20px;}
.title-box h1 { color: #000; background-color: #fff; display: inline; padding: 0 50px 0 50px; }
HTML
<div class="title-box"><h1>Title can go here</h1></div>
<div class="title-box"><h1>Title can go here this one is really really long</h1></div>
I am not experienced at all so feel free to correct things. However, I tried all these answers, but always had a problem in some screen.
So I tried the following that worked for me and looks as I want it in almost all screens with the exception of mobile.
<div class="wrapper">
<div id="Section-Title">
<div id="h2"> YOUR TITLE
<div id="line"><hr></div>
</div>
</div>
</div>
CSS:
.wrapper{
background:#fff;
max-width:100%;
margin:20px auto;
padding:50px 5%;}
#Section-Title{
margin: 2% auto;
width:98%;
overflow: hidden;}
#h2{
float:left;
width:100%;
position:relative;
z-index:1;
font-family:Arial, Helvetica, sans-serif;
font-size:1.5vw;}
#h2 #line {
display:inline-block;
float:right;
margin:auto;
margin-left:10px;
width:90%;
position:absolute;
top:-5%;}
#Section-Title:after{content:""; display:block; clear:both; }
.wrapper:after{content:""; display:block; clear:both; }

Resources