如何垂直对齐 CSS 中的所有文本?
How to vertically align all text in CSS?
问题似乎是 g
、y
、q
等尾部向下倾斜的某些字母不允许垂直居中。这是展示问题的图片 。
绿框里的字基本上是完美的,没有向下的尾巴。红框内的代表问题。
我希望所有字符都完全垂直居中。在图像中,尾巴向下的字符未垂直居中。这可以纠正吗?
Here is the fiddle that demonstrates the problem in full.
.avatar {
border-radius: 50%;
display: inline-block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
top: 50%;
transform: translateY(-50%);
line-height: 100%;
color: #fff;
}
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
为此您可能需要一个辅助类,这样您就可以更多地翻译小写字母而不是大写字母。一个简单的脚本可以轻松地自动启用这些助手 类。
希望这能解决您的问题:)
.avatar {
border-radius: 50%;
display: block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
top: 50%;
line-height: 100%;
color: #fff;
}
.character-lowercase {
transform: translateY(-60%);
}
.character-capital {
transform: translateY(-50%);
}
<div class="avatar">
<div class="character character-capital">W</div>
</div>
<div class="avatar">
<div class="character character-lowercase">y</div>
</div>
也许有更好的答案,但听起来唯一的方法是根据它是否是以下之一手动应用不同的样式:
- 大写字母
- 带尾巴的小写字母
- 带梗的小写
- 两者皆为小写
现在请注意,在我的理解中,我认为尾部和茎部的相对高度是由字体定义的。我不确定是否有办法以编程方式访问它 - 因此您可能需要使用字体调整这些值。
另请注意,此解决方案不适用于支持多种语言 - 因为您需要定义每个字符在数十个不同字符集中属于哪个类别。
const letters = ['a', 'b', 'y', 'X', 'c', 'y', 'A', 'B', 'Y'];
function getAdditionalClass(char){
//To do - fill arrays with the rest of the appropriate letters
if (['y', 'g'].includes(char)) {
return "tail";
}
if (['b', 'd'].includes(char)) {
return "stalk";
}
if (['a', 'c'].includes(char)) {
return "small";
}
return "capital";
}
letters.forEach(v => {
const avatar = document.createElement("div");
avatar.className = "avatar";
const character = document.createElement("div");
character.textContent = v;
character.className = `character ${getAdditionalClass(v)}`;
avatar.appendChild(character);
const root = document.getElementById("root");
root.appendChild(avatar);
});
.avatar {
border-radius: 50%;
display: block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
transform: translateY(-50%);
line-height: 100%;
color: #fff;
}
.small {
top: 45%;
}
.stalk {
top: 50%;
}
.tail {
top: 41%;
}
.capital {
top: 50%;
}
#root {
display: flex;
flex-flow: row wrap;
}
<div id = "root">
</div>
这是一个棘手的情况!
据我所知,这将最难实现本地可扩展性(即 %
、vw
或 vh
值而不是 px
或 em
).如果您需要使它在手机或平板电脑上看起来更漂亮,请考虑使用我的带有 @media
断点的解决方案。
我的解决方案本质上是检测它是否是一个 小写 元素 带有尾巴 并添加一个 class 来偏移高度来补偿尾巴。
在我的测试中,大写字母或小写字母[=38]似乎不需要任何额外的处理程序=]没有尾巴。如果我错了,请随时纠正我。
如果您想随意更改/测试此解决方案,可以使用 JSFiddle。
var circles = document.getElementsByClassName('circle');
var tails = ['q', 'y', 'p', 'g', 'j'] ;
Array.from(circles).forEach(render);
function render(element) {
if(element.innerText == element.innerText.toLowerCase() &&
tails.includes(element.innerText)) {
element.className += " scale";
}
}
.circle {
height: 150px;
width: 150px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
text-align: center;
vertical-align: middle;
line-height: 150px;
font-size: 50px;
}
.scale {
line-height: 135px;
}
<div>
<div class="circle">W</div>
<div class="circle">X</div>
</div>
<div>
<div class="circle">y</div>
<div class="circle">t</div>
</div>
让我知道您的想法,如果我遗漏了什么。得到最终解决方案会很酷,因为我自己过去也遇到过类似的问题!
这是我使用 JS 的解决方案。这个想法是将元素转换为图像,以便将其数据作为像素,然后循环遍历它们以找到每个字符的顶部和底部,并应用转换来修复对齐。这将适用于动态字体属性。
代码未优化但突出了主要思想:
var elems = document.querySelectorAll(".avatar");
var fixes = [];
for (var i = 0; i < elems.length; i++) {
var current = elems[i];
domtoimage.toPixelData(current)
.then(function(im) {
/* Search for the top limit */
var t = 0;
for (var y = 0; y < current.scrollHeight; ++y) {
for (var x = 0; x < current.scrollWidth; ++x) {
var j = (4 * y * current.scrollHeight) + (4 * x);
if (im[j] == 255 && im[j + 1] == 255 && im[j + 2] == 255) {
t = y;
break;
}
}
}
/* Search the bottom limit*/
var b = 0;
for (var y = (current.scrollHeight - 1); y >= 0; --y) {
for (var x = (current.scrollWidth - 1); x >= 0; --x) {
var j = (4 * y * current.scrollHeight) + (4 * x);
if (im[j] == 255 && im[j + 1] == 255 && im[j + 2] == 255) {
b = current.scrollHeight - y;
break;
}
}
}
/* get the difference and apply a translation*/
var diff = (b - t)/2;
fixes.push(diff);
/* we apply the translation when all are calculated*/
if(fixes.length == elems.length) {
for (var k = 0; k < elems.length; k++) {
elems[k].querySelector('.character').style.transform = "translateY(" + fixes[k] + "px)";
}
}
});
}
.avatar {
border-radius: 50%;
display: inline-flex;
vertical-align:top;
justify-content: center;
align-items: center;
width: 125px;
height: 125px;
font-size: 60px;
background:
linear-gradient(red,red) center/100% 1px no-repeat,
rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
color: #fff;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
<div class="avatar">
<div class="character" style="font-size:35px">a</div>
</div>
<div class="avatar">
<div class="character" style="font-size:25px">2</div>
</div>
<div class="avatar">
<div class="character">o</div>
</div>
<div class="avatar">
<div class="character">|</div>
</div>
<div class="avatar">
<div class="character">@</div>
</div>
<div class="avatar">
<div class="character">Â</div>
</div>
<div class="avatar">
<div class="character" style="font-family:arial">Q</div>
</div>
<div class="avatar">
<div class="character">~</div>
</div>
<div class="avatar">
<div class="character">8</div>
</div>
<div class="avatar">
<div class="character">ä</div>
</div>
<div class="avatar">
<div class="character">ç</div>
</div>
<div class="avatar">
<div class="character">$</div>
</div>
<div class="avatar">
<div class="character">></div>
</div>
<div class="avatar">
<div class="character">%</div>
</div>
更新
这里是代码的第一次优化:
var elems = document.querySelectorAll(".avatar");
var k = 0;
for (var i = 0; i < elems.length; i++) {
domtoimage.toPixelData(elems[i])
.then(function(im) {
var l = im.length;
/* Search for the top limit */
var t = 0;
for (var j = 0; j < l; j+=4) {
if (im[j+1] == 255) { /* Since we know the colors, we can only test the G composant */
t = Math.ceil((j/4)/125);
break;
}
}
/* Search the bottom limit*/
var b = 0;
for (var j = l - 1; j >= 0; j-=4) {
if (im[j+1] == 255) {
b = 125 - Math.ceil((j/4)/125);
break;
}
}
/* get the difference and apply a translation*/
elems[k].querySelector('.character').style.transform = "translateY(" + (b - t)/2 + "px)";
k++;
});
}
.avatar {
border-radius: 50%;
display: inline-flex;
vertical-align:top;
justify-content: center;
align-items: center;
width: 125px;
height: 125px;
font-size: 60px;
background:
linear-gradient(red,red) center/100% 1px no-repeat,
rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
color: #fff;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
<div class="avatar">
<div class="character" style="font-size:35px">a</div>
</div>
<div class="avatar">
<div class="character" style="font-size:25px">2</div>
</div>
<div class="avatar">
<div class="character">o</div>
</div>
<div class="avatar">
<div class="character">|</div>
</div>
<div class="avatar">
<div class="character">@</div>
</div>
<div class="avatar">
<div class="character">Â</div>
</div>
<div class="avatar">
<div class="character" style="font-family:arial">Q</div>
</div>
<div class="avatar">
<div class="character">~</div>
</div>
<div class="avatar">
<div class="character">8</div>
</div>
<div class="avatar">
<div class="character">ä</div>
</div>
<div class="avatar">
<div class="character">ç</div>
</div>
<div class="avatar">
<div class="character">$</div>
</div>
<div class="avatar">
<div class="character">></div>
</div>
<div class="avatar">
<div class="character">%</div>
</div>
我正在为此使用 dom-to-image 插件。
问题似乎是 g
、y
、q
等尾部向下倾斜的某些字母不允许垂直居中。这是展示问题的图片
绿框里的字基本上是完美的,没有向下的尾巴。红框内的代表问题。
我希望所有字符都完全垂直居中。在图像中,尾巴向下的字符未垂直居中。这可以纠正吗?
Here is the fiddle that demonstrates the problem in full.
.avatar {
border-radius: 50%;
display: inline-block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
top: 50%;
transform: translateY(-50%);
line-height: 100%;
color: #fff;
}
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
为此您可能需要一个辅助类,这样您就可以更多地翻译小写字母而不是大写字母。一个简单的脚本可以轻松地自动启用这些助手 类。
希望这能解决您的问题:)
.avatar {
border-radius: 50%;
display: block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
top: 50%;
line-height: 100%;
color: #fff;
}
.character-lowercase {
transform: translateY(-60%);
}
.character-capital {
transform: translateY(-50%);
}
<div class="avatar">
<div class="character character-capital">W</div>
</div>
<div class="avatar">
<div class="character character-lowercase">y</div>
</div>
也许有更好的答案,但听起来唯一的方法是根据它是否是以下之一手动应用不同的样式:
- 大写字母
- 带尾巴的小写字母
- 带梗的小写
- 两者皆为小写
现在请注意,在我的理解中,我认为尾部和茎部的相对高度是由字体定义的。我不确定是否有办法以编程方式访问它 - 因此您可能需要使用字体调整这些值。
另请注意,此解决方案不适用于支持多种语言 - 因为您需要定义每个字符在数十个不同字符集中属于哪个类别。
const letters = ['a', 'b', 'y', 'X', 'c', 'y', 'A', 'B', 'Y'];
function getAdditionalClass(char){
//To do - fill arrays with the rest of the appropriate letters
if (['y', 'g'].includes(char)) {
return "tail";
}
if (['b', 'd'].includes(char)) {
return "stalk";
}
if (['a', 'c'].includes(char)) {
return "small";
}
return "capital";
}
letters.forEach(v => {
const avatar = document.createElement("div");
avatar.className = "avatar";
const character = document.createElement("div");
character.textContent = v;
character.className = `character ${getAdditionalClass(v)}`;
avatar.appendChild(character);
const root = document.getElementById("root");
root.appendChild(avatar);
});
.avatar {
border-radius: 50%;
display: block;
text-align: center;
width: 125px;
height: 125px;
font-size: 60px;
background-color: rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
position: relative;
transform: translateY(-50%);
line-height: 100%;
color: #fff;
}
.small {
top: 45%;
}
.stalk {
top: 50%;
}
.tail {
top: 41%;
}
.capital {
top: 50%;
}
#root {
display: flex;
flex-flow: row wrap;
}
<div id = "root">
</div>
这是一个棘手的情况!
据我所知,这将最难实现本地可扩展性(即 %
、vw
或 vh
值而不是 px
或 em
).如果您需要使它在手机或平板电脑上看起来更漂亮,请考虑使用我的带有 @media
断点的解决方案。
我的解决方案本质上是检测它是否是一个 小写 元素 带有尾巴 并添加一个 class 来偏移高度来补偿尾巴。
在我的测试中,大写字母或小写字母[=38]似乎不需要任何额外的处理程序=]没有尾巴。如果我错了,请随时纠正我。
如果您想随意更改/测试此解决方案,可以使用 JSFiddle。
var circles = document.getElementsByClassName('circle');
var tails = ['q', 'y', 'p', 'g', 'j'] ;
Array.from(circles).forEach(render);
function render(element) {
if(element.innerText == element.innerText.toLowerCase() &&
tails.includes(element.innerText)) {
element.className += " scale";
}
}
.circle {
height: 150px;
width: 150px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
text-align: center;
vertical-align: middle;
line-height: 150px;
font-size: 50px;
}
.scale {
line-height: 135px;
}
<div>
<div class="circle">W</div>
<div class="circle">X</div>
</div>
<div>
<div class="circle">y</div>
<div class="circle">t</div>
</div>
让我知道您的想法,如果我遗漏了什么。得到最终解决方案会很酷,因为我自己过去也遇到过类似的问题!
这是我使用 JS 的解决方案。这个想法是将元素转换为图像,以便将其数据作为像素,然后循环遍历它们以找到每个字符的顶部和底部,并应用转换来修复对齐。这将适用于动态字体属性。
代码未优化但突出了主要思想:
var elems = document.querySelectorAll(".avatar");
var fixes = [];
for (var i = 0; i < elems.length; i++) {
var current = elems[i];
domtoimage.toPixelData(current)
.then(function(im) {
/* Search for the top limit */
var t = 0;
for (var y = 0; y < current.scrollHeight; ++y) {
for (var x = 0; x < current.scrollWidth; ++x) {
var j = (4 * y * current.scrollHeight) + (4 * x);
if (im[j] == 255 && im[j + 1] == 255 && im[j + 2] == 255) {
t = y;
break;
}
}
}
/* Search the bottom limit*/
var b = 0;
for (var y = (current.scrollHeight - 1); y >= 0; --y) {
for (var x = (current.scrollWidth - 1); x >= 0; --x) {
var j = (4 * y * current.scrollHeight) + (4 * x);
if (im[j] == 255 && im[j + 1] == 255 && im[j + 2] == 255) {
b = current.scrollHeight - y;
break;
}
}
}
/* get the difference and apply a translation*/
var diff = (b - t)/2;
fixes.push(diff);
/* we apply the translation when all are calculated*/
if(fixes.length == elems.length) {
for (var k = 0; k < elems.length; k++) {
elems[k].querySelector('.character').style.transform = "translateY(" + fixes[k] + "px)";
}
}
});
}
.avatar {
border-radius: 50%;
display: inline-flex;
vertical-align:top;
justify-content: center;
align-items: center;
width: 125px;
height: 125px;
font-size: 60px;
background:
linear-gradient(red,red) center/100% 1px no-repeat,
rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
color: #fff;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
<div class="avatar">
<div class="character" style="font-size:35px">a</div>
</div>
<div class="avatar">
<div class="character" style="font-size:25px">2</div>
</div>
<div class="avatar">
<div class="character">o</div>
</div>
<div class="avatar">
<div class="character">|</div>
</div>
<div class="avatar">
<div class="character">@</div>
</div>
<div class="avatar">
<div class="character">Â</div>
</div>
<div class="avatar">
<div class="character" style="font-family:arial">Q</div>
</div>
<div class="avatar">
<div class="character">~</div>
</div>
<div class="avatar">
<div class="character">8</div>
</div>
<div class="avatar">
<div class="character">ä</div>
</div>
<div class="avatar">
<div class="character">ç</div>
</div>
<div class="avatar">
<div class="character">$</div>
</div>
<div class="avatar">
<div class="character">></div>
</div>
<div class="avatar">
<div class="character">%</div>
</div>
更新
这里是代码的第一次优化:
var elems = document.querySelectorAll(".avatar");
var k = 0;
for (var i = 0; i < elems.length; i++) {
domtoimage.toPixelData(elems[i])
.then(function(im) {
var l = im.length;
/* Search for the top limit */
var t = 0;
for (var j = 0; j < l; j+=4) {
if (im[j+1] == 255) { /* Since we know the colors, we can only test the G composant */
t = Math.ceil((j/4)/125);
break;
}
}
/* Search the bottom limit*/
var b = 0;
for (var j = l - 1; j >= 0; j-=4) {
if (im[j+1] == 255) {
b = 125 - Math.ceil((j/4)/125);
break;
}
}
/* get the difference and apply a translation*/
elems[k].querySelector('.character').style.transform = "translateY(" + (b - t)/2 + "px)";
k++;
});
}
.avatar {
border-radius: 50%;
display: inline-flex;
vertical-align:top;
justify-content: center;
align-items: center;
width: 125px;
height: 125px;
font-size: 60px;
background:
linear-gradient(red,red) center/100% 1px no-repeat,
rgb(81, 75, 93);
font-family: "Segoe UI";
margin-bottom: 10px;
}
.character {
color: #fff;
}
<script type="text/javascript" src="https://css-challenges.com/wp-content/themes/ronneby_child/js/dom-to-image.js"></script>
<div class="avatar">
<div class="character">W</div>
</div>
<div class="avatar">
<div class="character">y</div>
</div>
<div class="avatar">
<div class="character" style="font-size:35px">a</div>
</div>
<div class="avatar">
<div class="character" style="font-size:25px">2</div>
</div>
<div class="avatar">
<div class="character">o</div>
</div>
<div class="avatar">
<div class="character">|</div>
</div>
<div class="avatar">
<div class="character">@</div>
</div>
<div class="avatar">
<div class="character">Â</div>
</div>
<div class="avatar">
<div class="character" style="font-family:arial">Q</div>
</div>
<div class="avatar">
<div class="character">~</div>
</div>
<div class="avatar">
<div class="character">8</div>
</div>
<div class="avatar">
<div class="character">ä</div>
</div>
<div class="avatar">
<div class="character">ç</div>
</div>
<div class="avatar">
<div class="character">$</div>
</div>
<div class="avatar">
<div class="character">></div>
</div>
<div class="avatar">
<div class="character">%</div>
</div>
我正在为此使用 dom-to-image 插件。