如何在CSS中垂直对齐所有文本?


12

这个问题似乎是某些字母一样gyq等有一个尾巴向下倾斜,不允许垂直居中。这是展示问题的图像一个

绿色框中的字符基本上是完美的,因为它们没有向下的尾巴。红色框中的内容演示了该问题。

我希望所有字符都垂直居中对齐。在图像中,尾巴向下的字符未垂直居中。这可以纠正吗?

这是充分说明问题的小提琴

.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>


1
这是个有趣的问题。答案可能在这里:iamvdo.me/en/blog/…–
dwjohnston

2
在这种情况下,您需要定义什么是中心。对我来说,y实际上居中,而A可能不在中心。让我们再谈谈当我们使用不同的字体系列时,对齐会变得更糟
Temani Afif

1
这就是信件的工作方式。它们对齐,因为v中的y和中的o部分g与大写字母的最低点在同一行。按照您的逻辑,Å,Ä,Ö会像A和O一样对齐,但不能对齐。如果您想对此做一些特别的事情,则需要使用javascript检查它是否是小写字母,然后将该字符微调几个字符。
RickardElimää19年

1
我很好奇这里是否有有用的答案。问题似乎在于这些内容确实是居中的。即。说您可以将y和g向上移动,如果您的小写字母a怎么办?应该如何显示?
dwjohnston

2
在任何字体编辑器中打开您的字体。编辑每个角色,直到您对看到的“居中”感到满意为止。保存并使用为全新的字体系列。应该不超过15分钟。除了SVG或其他使用canvas&co的骗术之外,我没有其他明智的方法。但是我会考虑这个问题。
Roko C. Buljan

Answers:


4

这是我使用JS的解决方案。想法是将元素转换为图像,以获取其数据作为像素,然后循环遍历它们以找到每个字符的顶部和底部,并应用平移来固定对齐方式。这将与动态字体属性一起使用。

该代码未进行优化,但突出了主要思想:

更新

这是代码的第一个优化:

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插件。


螨运行缓慢,但这是迄今为止第一个始终有效的解决方案。(请注意,以技术为中心的Â看起来很奇怪。)
Brilliand19年

@Brilliand我曾经明确Â地表明他的居中不是我回答中所说的最佳;)他可能会在看到这种情况后改变主意,并接受字体的工作方式
Temani Afif

看起来不错。如果可以提高效率,我想我会使用它。目前看来有点慢。
Chron包

@ChronBag是的,您可以处理代码并对其进行优化,这还有空间。我没有这样做,因为我花了很多时间,但这并不是问题的实质。我想专注于主要思想。可能会在以后做。
Temani Afif

@ChronBag添加了一个优化,我猜要快一点。
Temani Afif

1

也许有更好的答案,但是听起来唯一的方法就是根据是否为以下之一来手动应用不同的样式:

  • 大写字母
  • 带尾的小写
  • 带柄的小写字母
  • 小写字母都没有

现在注意,根据我的理解,我认为尾巴和茎的相对高度是由字体定义的。我不确定是否可以通过编程方式访问它-因此您可能需要使用字体调整这些值。

还要注意,该解决方案不适用于支持多种语言-因为您需要定义每个单个字符适合数十种不同字符集的类别。

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>


我希望避免这种情况,但这可能是唯一的解决方案。如果没有其他问题,我可能会使用它。谢谢
Chron Bag

2
如果该字母可以是任何Unicode字母(来自任何字母),那么这将变得不可行。
Brilliand

您会忘记ÂËâë
Temani Afif

好的,@ Brilliand我的用户将可以使用任何unicode文本作为其显示名称,因此该解决方案更加脆弱。
Chron Bag

0

这是一个棘手的情况!

据我所知,要实现本机可伸缩性(即%vw或者用vh值代替pxor em),这将是最困难的。如果您需要使它在手机或平板电脑上看起来很漂亮,请考虑将我的解决方案与@media断点一起使用。

我的解决方案实质上是检测它是否是带有尾巴小写元素并添加一个类以抵消高度以补偿尾巴。

在我的测试中,似乎没有大写字母或无尾的小写字母需要任何其他处理程序。如果我错了,请随时纠正我。

如果您想弄乱并更改/测试此解决方案,则可以使用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>

让我知道您的想法,如果我错过了任何事情。最终解决方案很不错,因为我过去也遇到过类似的问题!


这似乎与dwjohnston的解决方案相似,并且面临与他相同的陷阱。尽管如此,还是很感激的,如果没有更多的理想出现,我可能最终会遵循这些思路。
Chron Bag

我想,作为最后的手段,你可以下去像素计数的路径-因为看到这里,让你会发现它的实际高度以像素为单位,然后应用合适的偏移。
EGC

1
是的,我在给OP的评论中提到了这个想法。也许这就是要走的路。
Chron Bag

很抱歉再次注意到您的想法。.太多评论,显然错过了!
EGC

-1

为此,您可能需要一个helperclass,这样您可以翻译小写字母而不是大写字母。一个简单的脚本可以轻松地自动将这些帮助程序类放上。

希望这可以为您解决问题:)

.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>


y没有居中。Tweek还有更多!
Roko C. Buljan

我也提前不知道信件会是什么。
Chron Bag

我理解这一点,但是一个检查字母是否为大写或小写并在HTML的基础上放一个帮助器类的脚本可以轻松解决此问题:)
Ragna Roaldset

@RagnaRoaldset我认为他不是大写或小写。他的意思是存在小写字母但形状不同的字符。比较一下oy您会得到的。带有尾巴的字符首先会产生问题(在文章中提到)。
安娜,

1
您总是可以为所有带尾巴的字母创建一个数组,并在应用该类之前循环遍历以检查div中的字母是否匹配:)但是我明白了,只是想提供一个解决方案:)希望有人提出来它:)
拉格纳·罗尔德塞特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.