Jak wyrównać w pionie cały tekst w CSS?

12

Problem wydaje się, że niektóre litery, takie jak g, y, q, itd., Które mają ogon, które schodzą w dół, nie można dopuścić do pionowego centrowania. Oto zdjęcie przedstawiające problem za.

Postacie w zielonym polu są w zasadzie idealne, ponieważ nie mają ogona skierowanego w dół. Te w czerwonym polu pokazują problem.

Chciałbym, aby wszystkie postacie były idealnie wyśrodkowane pionowo. Na obrazie postacie z ogonem skierowanym w dół nie są wyśrodkowane pionowo. Czy można to naprawić?

Oto skrzypce, które w pełni demonstrują problem .

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

Torba chroniona
źródło
1
To interesujące pytanie. Odpowiedź może być tutaj: iamvdo.me/en/blog/…
dwjohnston
2
w takim przypadku musisz określić, co jest centrum . Dla mnie y jest właściwie wyśrodkowane, a A może nie. nie rozmawiajmy, kiedy mamy inną rodzinę czcionek, wyrównanie będzie jeszcze gorsze
Temani Afif
1
Właśnie tak działają litery. Są one wyrównane, ponieważ litery vin yi oczęść w gsą w tym samym wierszu, co najniższy punkt wielkich liter. Zgodnie z twoją logiką, Å, Ę, Ö byłyby zrównane tak jak A i O, ale nie mogą być. Jeśli chcesz zrobić coś wyjątkowego, musisz użyć javascript, aby sprawdzić, czy jest to mała czcionka, a następnie podnieść postać o kilka znaków.
Rickard Elimää
1
Jestem ciekawy, czy jest tu przydatna odpowiedź. Wydaje się, że problem polega na tym, że są one rzeczywiście wyśrodkowane. to znaczy. powiedz, że możesz przesunąć y i g w górę, co jeśli miałbyś małą a? jak to powinno się wyświetlać?
dwjohnston
2
Otwórz czcionkę w dowolnym edytorze czcionek. Edytuj każdą postać, aż będziesz zadowolony z tego, co postrzegasz jako „wyśrodkowane” . Zapisz i używaj jako swojej nowej rodziny czcionek. Powinien zająć nie więcej niż 15 min. Nie widzę innej zdrowej drogi oprócz SVG lub innych sztuczek wykorzystujących canvas & co. Ale pomyślę o tym pytaniu.
Roko C. Buljan

Odpowiedzi:

4

Oto moje rozwiązanie za pomocą JS. Chodzi o to, aby przekształcić element w obraz, aby uzyskać jego dane jako piksel, a następnie przejść przez nie, aby znaleźć górną i dolną część każdego znaku i zastosować tłumaczenie, aby naprawić wyrównanie. Będzie to działać z dynamicznymi właściwościami czcionek.

Kod nie jest zoptymalizowany, ale podkreśla główną ideę:

AKTUALIZACJA

Oto pierwsza optymalizacja kodu:

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>

Używam do tego wtyczki dom-to-image .

Temani Afif
źródło
Roztocza wolno działają, ale jest to pierwsze jak dotąd konsekwentnie działające rozwiązanie. (Z zastrzeżeniem, że technicznie wyśrodkowany  wygląda dziwnie.)
Brilliand
@Brilliand I wyraźnie pokazałem, Âże jego centrowanie nie jest optymalne, jak skomentowałem w jego odpowiedzi;) Prawdopodobnie zmieni zdanie po zobaczeniu tego i zaakceptuje sposób działania czcionki
Temani Afif
To wygląda całkiem nieźle. Myślę, że skorzystam z tego, jeśli mogę to uczynić bardziej wydajnym. Obecnie wydaje się nieco powolny.
Chron Bag
@ChronBag tak, możesz pracować nad kodem i zoptymalizować go, jest na to miejsce. Nie zrobiłem tego, ponieważ zajmuje mi to dużo czasu i nie jest to tak naprawdę celem pytania. Chciałem skupić się na głównej idei. Nawiasem mówiąc, zrobię to później.
Temani Afif,
@ChronBag dodał optymalizację, chyba trochę szybszą.
Temani Afif
1

Być może jest lepsza odpowiedź, ale wydaje się, że jedynym sposobem jest ręczne zastosowanie różnych stylów w zależności od tego, czy jest to jeden z:

  • Wielka litera
  • Małe litery z ogonem
  • Małe litery z łodygą
  • Małe litery bez żadnego

Zauważmy teraz, że moim zdaniem względne wysokości ogonów i łodyg są określone czcionką. Nie jestem pewien, czy istnieje sposób programowego dostępu do tego - może być konieczne dostosowanie tych wartości za pomocą czcionki.

Zauważ też, że to rozwiązanie nie działałoby w przypadku obsługi wielu języków - ponieważ musisz zdefiniować, którą kategorię pasuje każdy znak w dziesiątkach różnych zestawów znaków.

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
źródło
Miałem nadzieję uniknąć czegoś takiego, ale może to być jedyne rozwiązanie. Jeśli nic więcej się nie pojawi, prawdopodobnie skorzystam z tego. Dzięki
Chron Bag
2
Jeśli litera może być dowolną literą Unicode (z dowolnego alfabetu), staje się to niemożliwe.
Brilliand
Zapominasz ÂËiâë
Temani Afif
Ach tak, dobra uwaga @Brilliand. Moi użytkownicy będą mogli używać dowolnego tekstu Unicode do wyświetlania nazw, więc to rozwiązanie jest jeszcze bardziej kruche.
Chron Bag
0

To trudna sytuacja!

Z tego, co mogę powiedzieć, to będzie najtrudniejsza aby natywnie skalę (czyli %, vwczy vhwartości zamiast pxlub em). Jeśli chcesz, aby wyglądał ładnie na telefonie komórkowym lub tablecie, rozważ użycie mojego rozwiązania z @mediapunktami przerwania.

Moje rozwiązanie zasadniczo wykrywa, czy jest to mały element z ogonem i dodaje klasę do wyrównania wysokości w celu skompensowania ogona.

W moich testach nie wyglądało na to, że do obsługi wielkich lub małych liter bez ogona wymagane są dodatkowe funkcje obsługi . Jeśli się mylę, nie krępuj się i popraw mnie.

Istnieje JSFiddle, jeśli chcesz zadzierać i zmieniać / testować to rozwiązanie.

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>

Daj mi znać, co myślisz, a jeśli coś przeoczyłem. Byłoby fajnie znaleźć ostateczne rozwiązanie tego problemu, ponieważ sam miałem podobne problemy w przeszłości!

EGC
źródło
Wydaje się, że jest to podobne do rozwiązania dwjohnstona i podlega takim samym pułapkom jak jego. Niemniej jednak jest to doceniane i mogę skończyć z czymś podobnym, jeśli nie pojawi się nic bardziej idealnego.
Chron Bag
Przypuszczam, że w ostateczności możesz pójść ścieżką zliczania pikseli - jak widać tutaj , byś wykrył jej rzeczywistą wysokość w pikselach, a następnie zastosował odpowiednie przesunięcie.
EGC,
1
Tak, wspomniałem o tym pomyśle w komentarzach do PO. Może to jest właściwa droga.
Chron Bag
Przepraszam, że jeszcze raz zapoznałem się z Twoim pomysłem ... zbyt wiele komentarzy, oczywiście przegapiłem!
EGC
-1

Prawdopodobnie potrzebujesz do tego klasy pomocniczej, aby móc tłumaczyć małe litery bardziej niż wielkie litery. Prosty skrypt może łatwo ustawić te klasy pomocnicze automatycznie.

Mam nadzieję, że to rozwiąże problem dla ciebie :)

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

Ragna Roaldset
źródło
twoje ynie jest wyśrodkowane. Tweek jeszcze trochę!
Roko C. Buljan
Nie wiem też z góry, jakie będą litery.
Chron Bag
Rozumiem to, ale skrypt, który sprawdza, czy litera jest pisana wielkimi lub małymi literami i na tej podstawie umieszcza klasę pomocniczą w HTML, naprawi to łatwo :)
Ragna Roaldset,
@RagnaRoaldset Myślę, że nie ma na myśli wielkich i małych liter. Miał na myśli małą literę, ale inny kształt postaci. Porównaj, oa ydostaniesz to. Postacie z ogonami tworzą problem na pierwszym miejscu (wspomniane w poście).
Anna,
1
Zawsze możesz stworzyć tablicę dla wszystkich liter z ogonami i przejść przez nią, aby sprawdzić, czy litera w div pasuje przed zastosowaniem klasy :) Ale rozumiem, po prostu próbowałem znaleźć rozwiązanie :) mam nadzieję, że ktoś wymyśli to :)
Ragna Roaldset,