eb1
eb1

Reputation: 2947

Breaking to a new line with inline-block

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

Answers (3)

Temani Afif
Temani Afif

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>

CSS break line with inline-block


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>

multiline inline-block css


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

Nate Whittaker
Nate Whittaker

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

Dhiraj Mehta
Dhiraj Mehta

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

Related Questions