Як вертикально вирівняти весь текст у CSS?


12

Проблема , здається, що деякі букви , як g, y, qі т.д. , які мають хвіст , що нахили вниз, не дозволяють для вертикального центрування. Ось зображення для демонстрації проблемиа .

Персонажі в зеленому полі в основному ідеальні, оскільки у них немає хвоста вниз. Ті, хто знаходиться у червоному полі, демонструють проблему.

Я хотів би, щоб усі персонажі були ідеально вертикально по центру. На зображенні символи з низхідним хвостом не розташовані вертикально по центру. Чи можливо це виправити?

Ось загадка, яка демонструє проблему в повному обсязі .

.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, щоб перевірити, чи це маленька кришка, а потім підсунути персонаж на кілька символів.
Рікард Елімяа

1
Мені цікаво, чи є тут корисна відповідь. Проблема, здається, полягає в тому, що вони справді зосереджені. тобто. скажіть, ви можете перемістити y і g вгору, а як бути, якщо у вас було мале a? як це має відображатися?
dwjohnston

2
Відкрийте свій шрифт у будь-якому редакторі шрифтів. Редагуйте кожного персонажа, поки ви не задоволені тим, що вважаєте "центрованим" . Збережіть і використовуйте як нове сімейство шрифтів. Слід зайняти не більше 15 хв. Я не бачу іншого розумного способу, крім SVG чи інших хитрощів, що використовують canvas & co. Але я подумаю над цим питанням.
Roko C.

Відповіді:


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 я відверто використовував, Âщоб показати, що його центрування не є оптимальним, як я прокоментував його відповідь;) Він, певно, передумає, побачивши це, і прийме те, як працює шрифт
Temani 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>


Я сподівався уникнути чогось подібного, але це може бути єдине рішення. Якщо більше нічого не прийде, я, мабуть, цим скористаюся. Дякую
Chron Bag

2
Якщо літера може бути будь-якою літерою унікоду (з будь-якого алфавіту), то це стає нездійсненним.
Brilliand

Ви забудете ÂËіâë
Темані Афіф

Ага так, гарна точка @Brilliand Мої користувачі зможуть використовувати будь-який текст унікоду для своїх відображуваних імен, тому це рішення є ще більш крихким.
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не в центрі. Ще твіт!
Roko C.

Я також не знаю достроково, якими будуть букви.
Chron Bag

Я розумію це, але сценарій, який перевіряє, чи є літера великим чи малим літером, і вводить допоміжний клас на HTML, базуючись на тому, що це легко виправити :)
Рагна Роальдсет

@RagnaRoaldset Я думаю, що він не означає верхній чи нижній регістр. Він мав на увазі, що є малі, але різні форми характеру. Порівняйте, oі yви отримаєте це. Символи з хвостами створюють проблему в першу чергу (згадується в дописі).
Анна

1
Ви завжди можете створити масив для всіх букв з хвостами і провести цикл через нього, щоб перевірити, чи відповідає літера у діві перед застосуванням класу :) Але я це зрозумів, просто спробував знайти рішення :) сподіваюся, хтось придумає це :)
Рагна Роальдсет
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.