Как вертикально выровнять весь текст в CSS?

12

Проблема , кажется, что некоторые буквы , как g, y, qи т.д. , которые имеют хвост , что наклоны вниз, не позволяют для вертикального центрирования. Вот изображение, чтобы продемонстрировать проблему a.

Символы в зеленом поле в основном идеальны, так как у них нет нисходящего хвоста. Те, кто в красной коробке, демонстрируют проблему.

Я хотел бы, чтобы все персонажи были идеально вертикально отцентрированы. На изображении символы с нисходящим хвостом расположены не по центру. Можно ли это исправить?

Вот скрипка, которая в полной мере демонстрирует проблему .

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

Chron Bag
источник
1
Это интересный вопрос. Ответ может быть здесь: iamvdo.me/en/blog/…
dwjohnston
2
в этом случае вам нужно определить, что такое центр . Для меня у фактически центрирован, а А может и нет. давайте не будем говорить, когда у нас будет другое семейство шрифтов, выравнивание станет еще хуже
Темани Афиф
1
Вот как работают буквы. Они выровнены, потому что буквы vin yи opart в gтой же строке, что и нижняя точка заглавных букв. С вашей логикой, Å, Ä, Ö будут выровнены так же, как A и O, но они не могут быть. Если вы хотите сделать что-то особенное с этим, вам нужно использовать javascript, чтобы проверить, является ли он маленькой заглавной буквой, а затем подтолкнуть персонажа на несколько символов.
Рикард Элимяа
1
Мне любопытно, если здесь есть полезный ответ. Казалось бы, проблема в том, что они действительно центрированы. то есть. скажем, вы могли бы переместить Y и G вверх, а если бы у вас был строчный A? как это должно отображаться?
dwjohnston
2
Откройте свой шрифт в любом редакторе шрифтов. Редактируйте каждого персонажа до тех пор, пока вы не будете довольны тем, что считаете «центрированным» . Сохраните и используйте в качестве нового семейства шрифтов. Должно занять не более 15 мин. Я не вижу другого вменяемого способа, кроме SVG или других хитростей, использующих canvas & co. Но я подумаю над этим вопросом.
Roko C. Buljan

Ответы:

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 для этого.

Темани Афиф
источник
Клещ медленно работает, но пока это первое последовательно работающее решение. (С оговоркой, что технически-центрированно выглядит странно.)
Brilliand
@Brilliand я явно используется , Âчтобы показать , что его центрирование не является оптимальным , поскольку я прокомментировал в своем ответе;) Он, вероятно , изменит свое мнение после того, видя это и принять работы шрифтами путь
Феманитян Afif
Это выглядит довольно хорошо. Думаю, я воспользуюсь этим, если смогу сделать его более эффективным. В настоящее время это кажется немного медленным.
Chron Bag
@ ChronBag да, вы можете работать над кодом и оптимизировать его, для этого есть место. Я не делал этого, так как это занимало много времени, и это не совсем цель вопроса. Я хотел сосредоточиться на основной идее. Возможно, сделаю позже, кстати.
Темани Афиф
@ChronBag добавил оптимизацию, я думаю, немного быстрее.
Темани Афиф
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>

dwjohnston
источник
Я надеялся избежать чего-то подобного, но это может быть единственным решением. Если ничего не получится, я, вероятно, воспользуюсь этим. Спасибо
Chron Bag
2
Если буква может быть любой буквой Юникода (из любого алфавита), то это становится неосуществимым.
Brilliand
Вы забыли ÂËиâë
Темани Афиф
Ах да, хорошая идея @Brilliand Мои пользователи смогут использовать любой текст в Unicode для своих отображаемых имен, так что это решение еще более хрупкое.
Chron Bag
0

Это сложная ситуация!

Из того, что я могу сказать, это будет наиболее трудно сделать изначально масштабируемым (то есть %, vwили vhзначения вместо pxили 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>

Дайте мне знать ваши мысли, и если я что-то пропустил. Было бы здорово получить окончательное решение для этого, поскольку у меня были подобные проблемы в прошлом сам!

ЭГК
источник
Это похоже на решение Дуонстона и подвержено тем же ошибкам, что и его. Тем не менее, это ценится, и я мог бы в конечном итоге пойти по этому пути, если не будет ничего более идеального.
Chron Bag
Я полагаю, что в крайнем случае вы могли бы пойти по пути подсчета пикселей - как показано здесь, где вы бы обнаружили его фактическую высоту в пикселях, а затем применили соответствующее смещение.
EGC
1
Да, я упомянул эту идею в комментариях к ОП. Может быть, это путь.
Chron Bag
Извините, что снова заметил вашу идею ... слишком много комментариев, очевидно, пропустил это!
EGC
-1

Вам, вероятно, понадобится вспомогательный класс для этого, чтобы вы могли переводить строчные буквы больше, чем заглавные. Простой скрипт может легко включить эти вспомогательные классы автоматически.

Надеюсь, что это решит проблему для вас :)

.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не по центру. Еще немного!
Роко С.
Я также не знаю заранее, какие буквы будут.
Chron Bag
Я понимаю это, но скрипт, который проверяет, является ли буква прописными или строчными, и помещает вспомогательный класс в HTML на основе этого, легко это исправит :)
кто-то
@RagnaRoaldset Я думаю, он не имеет в виду верхний или нижний регистр. Он имел в виду строчную, но другую форму символа. Сравните, oи yвы получите это. Персонажи с хвостами создают проблему на первом месте (упоминается в посте).
Анна
1
Вы всегда можете создать массив для всех букв с хвостами и пройтись по нему, чтобы проверить, соответствует ли буква в div перед применением класса :) Но я понял, просто попытался найти решение :) надеюсь, кто-то придумает это :)
кто-то