Wie kann ich den gesamten Text in CSS vertikal ausrichten?

12

Die Frage scheint , dass bestimmte Buchstaben zu sein g, y, qetc. , das einen Schwanz hat , dass schräg nach unten geneigt, nicht für vertikale Zentrierung ermöglichen. Hier ist ein Bild, um das Problem zu veranschaulichen ein.

Die Zeichen in der grünen Box sind im Grunde perfekt, da sie keinen nach unten gerichteten Schwanz haben. Die in der roten Box gezeigten zeigen das Problem.

Ich möchte, dass alle Zeichen perfekt vertikal zentriert sind. Im Bild sind Zeichen mit einem nach unten gerichteten Ende nicht vertikal zentriert. Ist dies möglich zu korrigieren?

Hier ist die Geige, die das Problem vollständig demonstriert .

.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
quelle
1
Dies ist eine interessante Frage. Die Antwort könnte hier sein: iamvdo.me/en/blog/…
dwjohnston
2
In diesem Fall müssen Sie definieren, was das Zentrum ist . Für mich ist das y tatsächlich zentriert und das A vielleicht nicht. Lassen Sie uns nicht reden, wenn wir eine andere Schriftfamilie haben, die Ausrichtung wird noch schlechter
Temani Afif
1
So funktionieren Briefe. Sie sind ausgerichtet, da sich das vin yund ein oTeil in gderselben Zeile befinden wie der niedrigste Punkt für die Großbuchstaben. Mit Ihrer Logik würden Å, Ä, Ö genauso ausgerichtet sein wie A und O, aber sie können nicht sein. Wenn Sie etwas Besonderes tun möchten, müssen Sie Javascript verwenden, um zu überprüfen, ob es sich um eine Small-Cap handelt, und dann den Charakter um einige Zeichen nach oben schieben.
Rickard Elimää
1
Ich bin gespannt, ob es hier eine nützliche Antwort gibt. Das Problem scheint zu sein, dass diese wirklich zentriert sind. dh. Sagen Sie, Sie könnten das y und das g nach oben bewegen. Was wäre, wenn Sie ein Kleinbuchstaben a hätten? Wie soll das angezeigt werden?
Dwjohnston
2
Öffnen Sie Ihre Schrift in einem beliebigen Schrifteditor. Bearbeiten Sie jeden Charakter, bis Sie mit dem zufrieden sind, was Sie als "zentriert" betrachten . Speichern und als brandneue Schriftfamilie verwenden. Sollte nicht länger als 15 Minuten dauern. Ich sehe keinen anderen vernünftigen Weg als SVG oder andere Tricks mit Canvas & Co. Aber ich werde über diese Frage nachdenken.
Roko C. Buljan

Antworten:

4

Hier ist meine Lösung mit JS. Die Idee ist, das Element in ein Bild umzuwandeln, um seine Daten als Pixel zu erhalten, und sie dann zu durchlaufen, um die Ober- und Unterseite jedes Zeichens zu finden und eine Übersetzung anzuwenden, um die Ausrichtung zu korrigieren. Dies funktioniert mit dynamischen Schrifteigenschaften.

Der Code ist nicht optimiert, unterstreicht jedoch die Hauptidee:

AKTUALISIEREN

Hier ist eine erste Optimierung des Codes:

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>

Ich benutze dafür das Dom-to-Image- Plugin.

Temani Afif
quelle
Eine Milbe, die langsam läuft, aber dies ist die erste konsequent funktionierende Lösung, die es bisher gab. (Mit der Einschränkung, dass das technisch zentrierte seltsam aussieht.)
Brilliand
@Brilliand Ich habe explizit Âgezeigt, dass seine Zentrierung nicht optimal ist, wie ich in seiner Antwort kommentiert habe;) Er wird wahrscheinlich seine Meinung ändern, nachdem er dies gesehen hat und akzeptieren, wie Schrift funktioniert
Temani Afif
Das sieht ziemlich gut aus. Ich denke, ich werde das nutzen, wenn ich es effizienter machen kann. Derzeit scheint es ein bisschen langsam.
Chron Bag
@ChronBag ja du kannst am Code arbeiten und ihn optimieren, dafür ist Platz. Ich habe es nicht getan, da es viel Zeit in Anspruch nimmt und es nicht wirklich der Zweck der Frage ist. Ich wollte mich auf die Hauptidee konzentrieren. Wird wohl übrigens später machen.
Temani Afif
@ChronBag hat eine Optimierung hinzugefügt, etwas schneller, denke ich.
Temani Afif
1

Vielleicht gibt es eine bessere Antwort, aber es klingt so, als ob die einzige Möglichkeit darin besteht, verschiedene Stile manuell anzuwenden, je nachdem, ob es sich um einen der folgenden Stile handelt:

  • Großbuchstabe
  • Kleinbuchstaben mit Schwanz
  • Kleinbuchstaben mit einem Stiel
  • Kleinbuchstaben mit keinem

Beachten Sie nun, dass nach meinem Verständnis die relative Höhe der Schwänze und Stiele meiner Meinung nach durch die Schriftart definiert wird. Ich bin mir nicht sicher, ob es eine Möglichkeit gibt, programmgesteuert darauf zuzugreifen. Daher müssen Sie diese Werte möglicherweise mit der Schriftart anpassen.

Beachten Sie auch, dass diese Lösung nicht für die Unterstützung mehrerer Sprachen geeignet ist, da Sie definieren müssen, in welche Kategorie jedes einzelne Zeichen in Dutzende verschiedener Zeichensätze passt.

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
quelle
Ich hatte gehofft, so etwas zu vermeiden, aber es könnte die einzige Lösung sein. Wenn nichts anderes kommt, werde ich das wahrscheinlich benutzen. Vielen Dank
Chron Bag
2
Wenn der Buchstabe ein beliebiger Unicode-Buchstabe (aus einem beliebigen Alphabet) sein kann, funktioniert dies nicht mehr.
Brilliand
Sie vergessen das ÂËundâë
Temani Afif
Ah ja, guter Punkt @Brilliand Meine Benutzer können jeden Unicode-Text für ihre Anzeigenamen verwenden, daher ist diese Lösung noch spröder.
Chron Bag
0

Dies ist eine schwierige Situation!

Von dem, was ich sagen kann, wird dies am schwierigsten zu nativ skalierbar (dh zu machen %, vwoder vhWerten statt pxoder em). Wenn Sie dies auf Mobilgeräten oder Tablets hübsch gestalten möchten, sollten Sie meine Lösung mit @mediaHaltepunkten verwenden.

Meine Lösung erkennt im Wesentlichen , wenn es dich um ein Kleines Element mit einem Schwanz und fügt eine Klasse die Höhe zum Ausgleich für den Schwanz zu kompensieren.

In meinen Tests hat es nicht den Anschein , dass zusätzliche Handler für erforderlich waren Kapitalbuchstaben oder Kleinbuchstaben Buchstaben ohne Schwanz . Fühlen Sie sich frei, mich zu korrigieren, wenn ich falsch liege.

Es gibt eine JSFiddle, wenn Sie herumspielen und diese Lösung ändern / testen möchten.

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>

Lass mich deine Gedanken wissen und wenn ich etwas verpasst habe. Es wäre cool, eine endgültige Lösung dafür zu finden, da ich in der Vergangenheit selbst ähnliche Probleme hatte!

EGC
quelle
Dies scheint der Lösung von Dwjohnston ähnlich zu sein und unterliegt denselben Fallstricken wie seine. Trotzdem wird es geschätzt, und ich könnte am Ende etwas in diese Richtung tun, wenn nichts Idealeres zustande kommt.
Chron Bag
Ich nehme an, als letzten Ausweg könnten Sie den Weg der Pixelzählung beschreiten - wie hier gezeigt, wobei Sie die tatsächliche Höhe in Pixel erkennen und dann den entsprechenden Versatz anwenden würden.
EGC
1
Ja, ich habe diese Idee in den Kommentaren zum OP erwähnt. Vielleicht ist das der richtige Weg.
Chron Bag
Tut mir leid, dass ich Ihre Idee wieder notiert habe. Zu viele Kommentare, offensichtlich verpasst!
EGC
-1

Dazu benötigen Sie wahrscheinlich eine Hilfsklasse, damit Sie die Kleinbuchstaben mehr als die Großbuchstaben übersetzen können. Ein einfaches Skript kann diese Hilfsklassen einfach automatisch aktivieren.

Hoffe das löst das Problem für dich :)

.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
quelle
Ihr yist nicht zentriert. Tweek noch etwas!
Roko C. Buljan
Ich weiß auch nicht im Voraus, wie die Buchstaben lauten werden.
Chron Bag
Ich verstehe das, aber ein Skript, das prüft, ob der Buchstabe in Groß- oder Kleinbuchstaben geschrieben ist und eine darauf basierende Hilfsklasse in den HTML-Code einfügt, kann dies leicht beheben :)
Ragna Roaldset
@RagnaRoaldset Ich denke, er meint nicht Groß- oder Kleinschreibung. Er meinte, es gibt Kleinbuchstaben und doch eine andere Charakterform. Vergleichen Sie ound yund Sie werden das bekommen. Die Charaktere mit Schwänzen verursachen das Problem an erster Stelle (im Beitrag erwähnt).
Anna
1
Sie können jederzeit ein Array für alle Buchstaben mit Schwänzen erstellen und es durchlaufen, um zu überprüfen, ob der Buchstabe im div übereinstimmt, bevor Sie die Klasse anwenden :) Aber ich verstehe, ich habe nur versucht, eine Lösung zu finden :) Ich hoffe, jemand hat eine Idee it :)
Ragna Roaldset