html - How to make wrapped text's background span exactly across the pixel distance of that text?
问题描述
This is a problem I thought is simple enough for the modern CSS to solve and I'm really confused now. I wanted to make text parent's background to span exactly across the distance between left and right of it's longest text line, and spread evenly on the sides (not like the span element does)
It's obvious that the block elements automatically goes 100% width, and inline-block would be ok, if not the behavior of text's auto wrapping mechanism, which is making bounding box 100% size as it wraps first time to the line below.
I made a simulation of a desired effect, but this workarounds are somewhat ugly. I'm interested into more simple, native solution.
Fiddle + simulation: https://jsfiddle.net/sxmkonLp/20/
Normal block element text
<div class="container normal">
<h1 class="fill">Gonna wrap my text around</h1>
</div>
Parent element display: "inline-block" (a little closer)
<div class="container">
<h1 class="fill inl-blk">Gonna wrap my text around</h1>
</div>
Text inside "span" element (closer to what I need, but not evenly spread on the sides, depends on each separate line's length)
<div class="container">
<h1>
<span>Gonna wrap my text around</span>
</h1>
</div>
Desired result (simulating text breaks with br and classes)
<div class="container text-span">
<h1 class="fill2 inl-blk">Gonna<br class="sm4"> wrap<br class="sm3"> my<br class="sm2 sm4"> text<br class="sm1 sm3 sm4"> around</h1>
</div>
There goes CSS for the markup
html, body {
text-align: center;
margin: 0;
padding: 0;
}
.container {
padding: 10px;
width: auto;
background: orange;
margin: 10px;
}
.container span {
background: lightgreen;
padding: 5px;
}
.inl-blk {
display: inline-block;
}
.fill {
background: yellow;
}
.fill2 {
background: blueviolet;
color: white;
}
.sm1,.sm2,.sm3,.sm4 {display: none;}
@media screen and (max-width: 470px) {
.sm2 {display: none;}
.sm3 {display: none;}
.sm4 {display: none;}
.sm1 {display: block;}
}
@media screen and (max-width: 350px) {
.sm1 {display: none;}
.sm3 {display: none;}
.sm4 {display: none;}
.sm2 {display: block;}
}
@media screen and (max-width: 295px) {
.sm1 {display: none;}
.sm2 {display: none;}
.sm4 {display: none;}
.sm3 {display: block;}
}
@media screen and (max-width: 242px) {
.sm1 {display: none;}
.sm2 {display: none;}
.sm3 {display: none;}
.sm4 {display: block;}
}
As you can see in the last example (purple box) background occupies exactly the space of the text boundary. The problem is to make that happen while the text automatically wraps into the line below
I've made some discoveries recently, like this "exotic" CSS properties "box-decoration-break: clone;" which is making span's content more like separate, block lines, but still spans across separate line length, making it unusable for my current needs. It would be cool if we have some CSS property for exactly that.
解决方案
我已经为这个问题开发了非常简单的 JS 解决方案。最后,几乎每个网站最终都有大量的 javascript,所以我觉得它可以忍受。我们需要的只是这个惊人的包“css-element-queries”中的“ResizeSensor”
所以,我们得到了一个简单的容器,它用 h1 和 div 保存在我们的标题中,并带有一个类“title-bg”,它将成为标题的“虚拟响应背景”。它从显示设置为内联的 h1 获取精确的文本宽度。
<div class="container">
<div class="title">
<h1>Should I learn Scratch before programming?</h1>
<div class="title-bg"></div>
</div>
</div>
这里是 CSS,注意“.title-bg”是绝对定位的,所以它需要 transform-50% 的解决方案来保持居中。还需要 z-index: 1 for h1 可见。
.container {
max-width: 800px;
min-height: 320px;
padding: 20px;
background: #ccc;
margin: auto;
text-align: center;
}
.title {
overflow: hidden;
}
.title h1 {
display: inline;
/* background: orange; */
position: relative;
z-index: 1;
}
.title-bg {
background: teal;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
而对于 JS,我们只需要设置 ResizeSensor 来监听事件。出于某种原因,我无法让它直接与 h1 元素一起使用(当设置为 display: inline 时),所以我将它附加到标题 div。剩下的就是从 h1.offsetWidth 中获取值,这正是文本长度的值。瞧,准备好工作了!
let title = document.querySelector('.title')
let h1 = document.querySelector('.title h1')
let titleBg = document.querySelector('.title-bg')
// fire once on start
titleBg.style.width = `${h1.offsetWidth}px`
titleBg.style.height = `${h1.offsetHeight}px`
// init so it auto fires on element resize
new ResizeSensor(title, ()=> {
titleBg.style.width = `${h1.offsetWidth}px`
titleBg.style.height = `${h1.offsetHeight}px`
})
自己尝试:http: //jsfiddle.net/ktdfqhzo/52/
推荐阅读
- python - 同一列上的 Numpy.where 导致空数据框
- forms - 为什么自动建议菜单会将所选项目添加到多个输入中?
- html - 如何防止侧边栏滚动 flexdashboard 输入?R 和 Rmarkdwown
- flutter - 带有 TextField 的 setState 的 onChanged 方法不会更新结果?
- cocoapods - 是什么控制 CocoaPods 是显示登录页面还是仅显示 Git 存储库的链接?
- sql - 连接到多个服务器和数据库并运行相同的 SQL 语句
- vega - 在 vega 中将纪元时间戳转换为日期
- phpspreadsheet - 如何不使用 phpspreadsheet html 阅读器在单元格值中写入注释
- jenkins-pipeline - 在 Jenkinsfile 脚本内的字符串中添加括号会导致语法错误
- python - 如何使用 Tensorboard 绘制损失和准确度