CSS display: inline
элементы с текстом в них «перетекают» в конец строки, а затем переходят к следующей строке, когда контейнер для них недостаточно велик.
Я хочу добиться того же эффекта горизонтального переноса, но с элементами блока, шириной которых я могу управлять.
Если я используйте display: inline-block
, это позволяет мне контролировать ширину блока, но затем предотвращает разрыв строки.
Кажется, я не могу найти ничего набор CSS настроек, которые позволят мне как обтекать, так и контролировать ширину элемента. Однако кажется, что это должно быть возможно. Предположительно внутренне собственный механизм компоновки браузера делает это после того, как вычисляет ширину различных текстовых строк.
Я рассмотрел два обходных пути, которые дают мне желаемый визуальный результат:
- Установите моноширинный шрифт и заполните встроенные элементы рассчитанным правильным количеством текстовых символов, которые затем скрываются. У этого есть проблемы с тем фактом, что текст все еще существует и его можно выбрать на странице.
- Используйте javascript, когда элемент встроенного блока должен переноситься и вводить два блока меньшего расчетного размера, один для первого раздела и один на остаток. Это очень медленно при работе с большим количеством этих блоков.
Ни одно из этих решений не очень хорошее, и если это возможно чисто CSS, я очень хочу узнать, как это сделать.
Вот ссылка на примеры на скриншотах, отображаемых в интерактивном режиме:
https://jsfiddle.net/n3wzd29v/
let tags = document.getElementsByClassName("js");
let currentLeft = 0;
for (let i=0; i<tags.length; i++) {
let tag = tags[i];
// dont know how to get the "width this would be if it was not inline cleanly".
tag.style.display="inline-block";
let requestedWidth = tag.offsetWidth;
tag.style.display="inline";
let parentWidth = tag.parentNode.offsetWidth;
console.log("requestedWidth:" + requestedWidth);
console.log("parentWidth:" + parentWidth);
console.log("currentLeft:" + currentLeft);
//FIXME: handle spanning over arbitary number of lines.
if ((currentLeft + requestedWidth) < parentWidth) {
// Got plenty of space for this element on this line so just make it a inline-block
tag.style.display = "inline-block";
currentLeft += requestedWidth;
console.log("Just setting inline-block, its wide enough");
} else {
// This element needs breaking up into two elements, one for the part that fits on this
// line, and another for the remainder on the next line.
let part1Width = parentWidth - currentLeft;
let part1 = document.createElement("span");
part1.style.display = "inline-block"
part1.style.width = part1Width + "px";
part1.style.verticalAlign = "top";
part1.style.height = "16px";
let part2Width = requestedWidth - part1Width;
let part2 = document.createElement("span");
part2.style.display = "inline-block"
part2.style.width = part2Width + "px";
part2.style.verticalAlign = "top";
part2.style.height = "16px";
currentLeft = 0 + part2Width;
tag.appendChild(part1);
tag.appendChild(part2);
console.log("Adding two fixed width children: " + part1Width + " " + part2Width);
}
}
.container {
width: 200px;
background-color: lightblue;
}
span {
word-break: break-all;
font-family: monospace;
}
.bad {
display: inline-block;
height: 16px;
}
.stuffed {
line-height:22px;
}
.js {
height: 15px;
vertical-align: top;
}
.color1 {
background-color: hsl(0, 80%, 50%);
}
.color2 {
background-color: hsl(20, 80%, 50%);
}
.color3 {
background-color: hsl(40, 80%, 50%);
}
.color4 {
background-color: hsl(60, 80%, 50%);
}
.color1.stuffed {
color: hsl(0, 80%, 50%);
}
.color2.stuffed {
color: hsl(20, 80%, 50%);
}
.color3.stuffed {
color: hsl(40, 80%, 50%);
}
.color4.stuffed {
color: hsl(60, 80%, 50%);
}
<html>
<body>
<p>Inline elements with text in them "flow" over the end of a line
and then carry on the next line when the container isn't large enough for them.
</p>
<div class="container">
<span class="good color1">These inline</span><span class="good color2">spans will wrap over</span><span class="good color3">the end of the container</span><span class="good color4">exactly how i would like them to</span>
</div>
<br/>
<p>
However i want to do the same layout but with block elements that i can set
the width of. Using inline-block allows me to control the block width however
it seems to prevent line-breaking from working.
</p>
<div class="container">
<span class="bad color1" style="width:96px"></span><span class="bad color2" style="width:160px"></span><span class="bad color3" style="width:192px"></span><span class="bad color4" style="width:256px"></span>
</div>
<p>
Obviously i can acheieve something of the same behaviour by stuffing my inline
elements with hidden text, but that seems sub-optimal
</p>
<div class="container">
<span class="stuffed color1">████████████</span><span class="stuffed color2">████████████████████</span><span class="stuffed color3">████████████████████████</span><span class="stuffed color4">████████████████████████████████</span>
</div>
<p>
Finally, it is ofc also possible to fix this problem in javascript, but i'm tenative
to do layout in javascript when the browser already clearly have a well optimised
layout engine for doing this on text already.
</p>
<div class="container">
<span class="js color1" style="width:96px"></span><span class="js color2" style="width:160px"></span><span class="js color3" style="width:192px"></span><span class="js color4" style="width:256px"></span>
</div>
<br/>
<br/>
<br/>
</body>
</html>