Reputation: 2947
I've run into some layout overlap issues with a css float
container recently, and had started looking at using display: inline-block
instead. So far, so good... except I need to be able to add line-breaks, as clear
does for floats. Some sample text...
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
border: 1px solid #0cc;
display: inline-block;
padding: 3px;
}
<div class="container">
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
Is it possible to have my .block-start
<div>
elements start a new line?
EDIT: I should mention that each .block-start
element needs to be inline with the other ib
blocks, like a chapter number.
Upvotes: 2
Views: 557
Reputation: 272797
One hacky idea is to add a new line using pseudo element and make the element inline
so that the line-break will affect the inline-block
elements. The drawback is that you will not be able to style an inline
element like you do with an inline-block
one
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
display: inline;
padding: 3px;
white-space: pre-wrap;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "\A";
}
/* to rectify the position of the first one*/
.block-start:first-child {
padding-left: 0;
}
<div class="container">
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
To keep the styling (the border in this case) we can consider more hacks:
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
display: inline;
padding: 3px 3px 4px;
white-space: pre-wrap;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "\A";
}
/* to rectify the position of the first one*/
.block-start:first-child {
padding-left: 0;
border:1px solid red;
}
.block-start:not(:first-child) {
border:1px solid transparent;
border-right-color:red; /*the right is not an issue*/
background:
linear-gradient(red,red) top right / calc(100% - 3px) 1px,
linear-gradient(red,red) bottom right / calc(100% - 3px) 1px,
linear-gradient(red,red) left 4px top 0 / 1px 100%;
background-repeat:no-repeat;
background-origin:border-box;
padding-right:4px;
}
<div class="container">
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
As we can see, the padding-left
is the issue here since it's applied to the pseudo element creating the line break. One idea to fix this is to consider box-decoration-break
but we will have a small drawback at the end of each line:
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
display: inline;
padding: 3px 3px 4px;
white-space: pre-wrap;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
border:1px solid red;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "\A";
}
<div class="container">
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
We can still fix this by adding some negative margin in order to hide it behind the other elements (we should also add background color)
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
background:#fff;
position:relative;
}
.block-start {
display: inline;
padding: 3px 3px 4px;
white-space: pre-wrap;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
border:1px solid red;
margin-left:-15px;
}
.container {
padding-left:15px;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "\A";
}
<div class="container">
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start">block-start</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
We can also consider the other pseudo element and data-attribute to have more control over the styling wihout any hacks. This is the solution I recommend
I have used the class
attribute but you can consider a custom one in case you want a different content.
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
display: inline;
white-space: pre-wrap;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "\A";
}
.block-start:after {
content: attr(class);
display:inline-block;
border:1px solid red;
padding: 3px;
}
<div class="container">
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
The same trick can also work if you want to clear after
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-end {
display: inline;
white-space: pre-wrap;
}
/* Create the break line */
.block-end:not(:first-child):after {
content: "\A";
}
.block-end:before {
content: attr(class);
display: inline-block;
padding: 3px;
border:1px solid red;
}
<div class="container">
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-end"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-end"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-end"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
Here is some variation of the same idea that can be useful in other situation
With flexbox:
.container {
display:flex;
flex-wrap:wrap;
align-items:center;
}
.ib {
border: 1px solid #333;
padding: 3px;
background:#fff;
position:relative;
margin:0 3px 0;
}
.ib + .ib {
margin-left:0;
}
.block-start {
display: contents;
}
.container {
padding-left:15px;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "";
flex-basis:100%;
height:1px;
}
/* Will replace the content*/
.block-start:after {
content: attr(class);
border:1px solid red;
padding: 3px;
}
<div class="container">
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
With CSS grid:
.container {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(90px,1fr));
grid-gap:2px;
align-items:center;
}
.ib {
border: 1px solid #333;
padding: 3px;
background:#fff;
position:relative;
}
.block-start {
display: contents;
}
.container {
padding-left:15px;
}
/* Create the break line */
.block-start:not(:first-child):before {
content: "";
grid-column:1/-1;
}
/* Will replace the content*/
.block-start:after {
content: attr(class);
border:1px solid red;
padding: 3px;
}
<div class="container">
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
Another one with CSS grid:
.container {
display:grid;
grid-template-columns:repeat(10000,max-content);
grid-gap:2px;
align-items:center;
}
.ib {
border: 1px solid #333;
padding: 3px;
background:#fff;
position:relative;
}
.container {
padding-left:15px;
}
/* Create the break line */
.block-start {
grid-column:1;
border:1px solid red;
padding: 3px;
}
/* Will replace the content*/
.block-start:after {
content: attr(class);
}
<div class="container">
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="block-start"></div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
Upvotes: 7
Reputation: 1966
What you're describing sounds like a Run-In Layout:
A run-in box is a box that merges into a block that comes after it, inserting itself at the beginning of that block’s inline-level content. This is useful for formatting compact headlines, definitions, and other similar things, where the appropriate DOM structure is to have a headline preceding the following prose, but the desired display is an inline headline laying out with the text. [1]
However, browser support is currently very poor and, in some cases, has regressed[2]. If you have control over the mark-up, wrapping each group of .ib
and .block-start
elements in a new block-level tag is probably your best bet.
[1] https://drafts.csswg.org/css-display/#run-in-layout
[2] https://caniuse.com/#feat=run-in
Upvotes: 0
Reputation: 31
In .block-start
selector simply change display:inline-block
property to display:block
. And also change the html <div>
as shown below
I hope this will work.
.ib {
border: 1px solid #333;
display: inline-block;
padding: 3px;
}
.block-start {
border: 1px solid #0cc;
display: block;
padding: 3px;
}
<div class="container">
<div class="block-start">block-start
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
<div class="block-start">block-start
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
<div class="ib">inline-block</div>
</div>
</div>
Upvotes: -2