Comment aligner verticalement tout le texte en CSS?

12

La question semble être que certaines lettres comme g, y, q, etc. , qui ont une queue vers le bas des pentes, ne permettent pas de centrage vertical. Voici une image pour présenter le problème une.

Les personnages dans la boîte verte sont fondamentalement parfaits, car ils n'ont pas de queue vers le bas. Ceux dans la case rouge montrent le problème.

J'aimerais que tous les personnages soient parfaitement centrés verticalement. Dans l'image, les personnages avec une queue vers le bas ne sont pas centrés verticalement. Est-ce possible de rectifier?

Voici le violon qui illustre pleinement le problème .

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

Sac Chron
la source
1
C'est une question intéressante. La réponse pourrait être ici: iamvdo.me/en/blog/…
dwjohnston
2
dans ce cas, vous devez définir ce qu'est le centre . Pour moi, le y est en fait centré et le A peut-être pas. ne parlons pas quand nous avons une famille de polices différente, l'alignement va encore empirer
Temani Afif
1
C'est comme ça que les lettres fonctionnent. Ils sont alignés, car le vdans yet la opartie dans le gsont sur la même ligne que le point le plus bas pour les majuscules. Avec votre logique, Å, Ä, Ö seraient alignés tout comme A et O mais ils ne peuvent pas l'être. Si vous voulez faire quelque chose de spécial à ce sujet, vous devez utiliser javascript pour vérifier s'il s'agit d'une petite majuscule, puis pousser le caractère de quelques caractères.
Rickard Elimää
1
Je suis curieux de savoir s'il y a une réponse utile ici. Le problème semble être que ceux-ci sont véritablement centrés. c'est à dire. dites que vous pouvez déplacer le y et le g vers le haut, et si vous aviez un a en minuscule? comment cela devrait-il s'afficher?
dwjohnston
2
Ouvrez votre police dans n'importe quel éditeur de polices. Modifiez chaque personnage jusqu'à ce que vous soyez satisfait de ce que vous voyez comme "centré" . Enregistrez et utilisez comme toute nouvelle famille de polices. Ne devrait pas prendre plus de 15 minutes. Je ne vois pas d'autre moyen sensé que SVG ou d'autres ruses en utilisant canvas & co. Mais je vais réfléchir à cette question.
Roko C. Buljan

Réponses:

4

Voici ma solution en utilisant JS. L'idée est de transformer l'élément en image afin d'obtenir ses données sous forme de pixel puis de les parcourir pour trouver le haut et le bas de chaque caractère et appliquer une traduction pour fixer l'alignement. Cela fonctionnera avec les propriétés de police dynamique.

Le code n'est pas optimisé mais il met en évidence l'idée principale:

MISE À JOUR

Voici une première optimisation du code:

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>

J'utilise le plugin dom-to-image pour cela.

Temani Afif
la source
Un acarien qui fonctionne lentement, mais c'est la première solution qui fonctionne de manière cohérente jusqu'à présent. (Avec la mise en garde que le techniquement centré a l'air bizarre.)
Brilliand
@Brilliand J'ai explicitement Âmontré que son centrage n'est pas optimal comme je l'ai commenté dans sa réponse;) Il changera probablement d'avis après avoir vu cela et acceptera le fonctionnement de la police
Temani Afif
Cela semble assez bon. Je pense que je vais l'utiliser, si je peux le rendre plus efficace. Actuellement, cela semble un peu lent.
Chron Bag
@ChronBag oui vous pouvez travailler sur le code et l'optimiser, il y a de la place pour cela. Je ne l'ai pas fait car cela me prend beaucoup de temps et ce n'est pas vraiment le but de la question. Je voulais me concentrer sur l'idée principale. Le fera probablement plus tard d'ailleurs.
Temani Afif
@ChronBag a ajouté une optimisation, un peu plus rapide je suppose.
Temani Afif
1

Il y a peut-être une meilleure réponse, mais il semble que la seule façon de le faire soit d'appliquer manuellement différents styles selon qu'il s'agit de l'un des:

  • Lettre capitale
  • Minuscule avec une queue
  • Minuscule avec une tige
  • Minuscule avec ni l'un ni l'autre

Notez maintenant que, à ma connaissance, la hauteur relative des queues et des tiges, je pense, est définie par la police. Je ne sais pas s'il existe un moyen d'accéder à cela par programmation - vous devrez donc peut-être ajuster ces valeurs avec la police.

Notez également que cette solution ne fonctionnerait pas pour la prise en charge de plusieurs langues - car vous auriez besoin de définir dans quelle catégorie chaque caractère s'inscrit dans des dizaines de jeux de caractères différents.

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
la source
J'espérais éviter quelque chose comme ça, mais c'est peut-être la seule solution. Si rien d'autre ne vient, je vais probablement l'utiliser. Merci
Chron Bag
2
Si la lettre peut être n'importe quelle lettre unicode (de n'importe quel alphabet), cela devient impossible.
Brilliand
Vous oubliez le ÂËetâë
Temani Afif
Ah ouais, bon point @Brilliand Mes utilisateurs pourront utiliser n'importe quel texte Unicode pour leurs noms d'affichage, donc cette solution est encore plus fragile.
Chron Bag
0

C'est une situation délicate!

D'après ce que je peux dire, ce sera plus difficile à rendre nativement évolutif (c'est %-à- dire , vwou des vhvaleurs au lieu de pxou em). Si vous avez besoin de rendre cela joli sur mobile ou tablette, veuillez envisager d'utiliser ma solution avec@media points arrêt.

Ma solution détecte essentiellement s'il s'agit d'un élément en minuscule avec une queue et ajoute une classe pour compenser la hauteur pour compenser la queue.

Dans mes tests, il ne semble pas que les gestionnaires supplémentaires étaient nécessaires pour fonds propres lettres ou minuscules lettres sans queue . N'hésitez pas à me corriger si je me trompe.

Il y a un JSFiddle si vous voulez déconner et changer / tester cette solution.

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>

Faites-moi savoir vos pensées et si j'ai raté quelque chose. Ce serait cool d'avoir une solution finale pour cela car j'ai moi-même eu des problèmes similaires dans le passé!

EGC
la source
Cela semble être similaire à la solution de dwjohnston et soumis aux mêmes pièges que le sien. Néanmoins, il est apprécié et je pourrais finir par aller dans ce sens si rien de plus idéal ne se présente.
Chron Bag
Je suppose qu'en dernier recours, vous pourriez suivre le chemin du comptage de pixels - comme on le voit ici, par lequel vous détecteriez sa hauteur réelle en pixels, puis appliquer le décalage approprié.
EGC
1
Oui, j'ai mentionné cette idée dans les commentaires au PO. C'est peut-être la voie à suivre.
Chron Bag
Désolé de noter à nouveau votre idée .. trop de commentaires, évidemment raté!
EGC
-1

Vous auriez probablement besoin d'une classe d'aide pour cela, afin que vous puissiez traduire les lettres minuscules plus que les lettres majuscules. Un script simple peut facilement activer automatiquement ces classes d'assistance.

J'espère que cela résout le problème pour vous :)

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

Quelqu'un
la source
votre yn'est pas centré. Tweek un peu plus!
Roko C. Buljan
Je ne sais pas non plus à l'avance quelles seront les lettres.
Chron Bag
Je comprends cela, mais un script qui vérifie si la lettre est en majuscules ou en minuscules et met une classe d'assistance sur le HTML basé sur cela corrigera cela facilement :)
quelqu'un
@RagnaRoaldset Je pense qu'il ne veut pas dire majuscule ou minuscule. Il voulait dire qu'il y a une forme de caractère en minuscule mais différente. Comparez oet yvous obtiendrez cela. Les personnages avec des queues créent le problème en premier lieu (mentionné dans le post).
Anna
1
Vous pouvez toujours créer un tableau pour toutes les lettres avec des queues et le parcourir pour vérifier si la lettre dans le div correspond avant d'appliquer la classe :) Mais je comprends, j'ai juste essayé de trouver une solution :) j'espère que quelqu'un trouvera it :)
quelqu'un