69 votes

redimensionner la police pour qu'elle tienne dans un div (sur une ligne)

Des questions similaires ont été posées, mais les solutions correspondent à ce que j'essaie de faire. En gros, j'ai un article avec un titre ( <h1> ). Je ne veux pas contrôler la longueur du titre, mais je ne veux pas non plus que le titre apparaisse sur plusieurs lignes. Existe-t-il un moyen, avec css ou jQuery, de redimensionner le texte en fonction de la largeur d'un <div> tag ?

Je sais ce que je ferais avec le pseudocode si je pouvais détecter le chevauchement du texte par rapport au bord de l'écran. <div> :

var fontize = $("#title").css("font-size");
var i = /*remove unit from integer*/
while( /*text overlaps div*/ ){
    $("#title").css("font-size", --i+"pt");
}

S'il y a un attribut CSS que je peux définir, ce serait encore mieux, mais je n'arrive pas à en trouver un (overflow ne fonctionnerait pas dans cette situation).

1 votes

J'aime l'attitude consistant à préférer un CSS solution. En effet, elle est plus agréable car elle permet également un affichage correct pour les utilisateurs qui n'activent pas ou ne peuvent pas utiliser Javascript (il peut y avoir des raisons à cela).

3 votes

Je n'arrive pas à croire que css3 n'a pas de fonctionnalité à ce sujet. C'est tellement sale en JS ... et ça doit être un besoin tellement commun maintenant avec le monde réactif !

0 votes

49voto

Robert Koritnik Points 45499

CSS non, Javascript oui

Il n'y a aucun moyen de faire cela en utilisant CSS, mais vous pouvez le faire en javascript/jQuery. Pour vous aider avec votre pseudo code car vous savez déjà ce qu'il faut faire. C'est juste que vous ne savez pas comment détecter la largeur excessive.

La meilleure solution serait d'avoir un DIV avec le style suivant (au moins) :

position: absolute;
visibility: hidden;
white-space: nowrap;
font-family: /* same as your title's */

puis copiez-y votre texte et définissez une taille de police de départ. Vous pouvez ensuite itérer dans votre boucle while et vous arrêter lorsque la largeur de la division est appropriée. Définissez ensuite la taille de la police calculée pour votre titre original.

De cette façon, ce contrôle sera caché aux yeux de l'utilisateur et il fonctionnera donc plus rapidement.

BTW : C'est la façon habituelle de faire de l'auto-culture textarea scripts fonctionnent. Ils utilisent des divs fictifs avec les mêmes paramètres de style que la zone de texte originale et ajustent la hauteur de la zone au fur et à mesure que l'utilisateur tape du texte. Ainsi, la zone de texte peut être assez petite au début, mais si l'utilisateur tape beaucoup de texte, elle s'agrandira automatiquement pour s'adapter au contenu.

Optimisation de la boucle While

Vous pourriez optimiser votre boucle while pour réduire considérablement le nombre d'itérations en procédant ainsi :

  1. Définissez une taille de police de départ.
  2. obtenir la largeur du DIV de test.
  3. calculer le facteur de largeur entre orig_div et test_div.
  4. ajuster la taille de la police par ce facteur plutôt que d'augmenter/diminuer d'une unité
  5. test test_div largeur

1 votes

C'est intéressant. Donc, en gros, je peux utiliser une div cachée pour obtenir la largeur, puis dans la balise while(test_div.width > title_div.width) faites mon décrément. C'est du roman. Merci.

2 votes

@Tim : Vérifiez mes informations supplémentaires dans la réponse concernant l'optimisation de la boucle while. Cela devrait accélérer un peu les choses.

4 votes

Je vous donnerai du karma si quelqu'un fait un bidule qui fonctionne ;p

24voto

chunks_n_bits Points 154

J'ai eu un problème similaire, ce qui m'a poussé à écrire mon propre plugin pour cela. Jetez un coup d'oeil à jquery-quickfit (qui est assez similaire à Robert Koritnik que j'aime beaucoup).

Afin d'empêcher le titre de s'étendre sur plusieurs lignes, il suffit d'ajouter un style css de :

white-space:nowrap;

à l'élément.

Après avoir inclus jquery et quickfit dans l'en-tête. Vous pouvez déclencher quickfit avec :

$('h1').quickfit();

Il mesure et calcule une mesure invariable en fonction de la taille pour chaque lettre du texte à insérer et l'utilise pour calculer la taille de police suivante qui convient le mieux au texte dans le conteneur.

Les calculs sont mis en cache, ce qui le rend très rapide lorsqu'il s'agit d'adapter plusieurs textes ou d'adapter un texte plusieurs fois, comme par exemple lors du redimensionnement de la fenêtre (il n'y a pratiquement aucune perte de performance lors du redimensionnement).

Démonstration pour une situation similaire à la vôtre

De la documentation supplémentaire, des exemples et le code source sont disponibles sur la page du projet.

1 votes

"Il y a une bibliothèque pour ça !"

2 votes

Et la bibliothèque est un oneliner :P (fittextjs)

19 votes

Tout le JavaScript est une ligne unique si vous enlevez les sauts de ligne !

20voto

Clovis Six Points 111

Voici 3 fonctions que j'utilise fréquemment pour obtenir la largeur et la hauteur du texte et ajuster la taille à la largeur du conteneur.

  • getTextWidth() vous renverra la largeur réelle du texte contenu dans l'initiateur.
  • getTextHeight(width) renvoie la hauteur réelle du texte enveloppé contenu dans l'initiateur avec une certaine largeur spécifiée.
  • autoTextSize(minSize, maxSize, truncate) permet de dimensionner le texte dans le conteneur de manière à ce qu'il soit adapté, en tenant compte d'une taille minimale et maximale.
  • autoTruncateText() n'affichera que les caractères que l'utilisateur peut réellement voir et terminera le texte par "...".

    (function ($) { $.fn.getTextWidth = function() { var spanText = $("BODY #spanCalculateTextWidth");

    if (spanText.size() <= 0) {
      spanText = $("<span id='spanCalculateTextWidth' style='filter: alpha(0);'></span>");
      spanText.appendTo("BODY");
    }
    
    var valu = this.val();
    if (!valu) valu = this.text();
    
    spanText.text(valu);
    
    spanText.css({
      "fontSize": this.css('fontSize'),
      "fontWeight": this.css('fontWeight'),
      "fontFamily": this.css('fontFamily'),
      "position": "absolute",
      "top": 0,
      "opacity": 0,
      "left": -2000
    });
    
    return spanText.outerWidth() + parseInt(this.css('paddingLeft')) + 'px';

    };

    $.fn.getTextHeight = function(width) { var spanText = $("BODY #spanCalculateTextHeight");

    if (spanText.size() <= 0) {
      spanText = $("<span id='spanCalculateTextHeight'></span>");
      spanText.appendTo("BODY");
    }
    
    var valu = this.val();
    if (!valu) valu = this.text();
    
    spanText.text(valu);
    
    spanText.css({
      "fontSize": this.css('fontSize'),
      "fontWeight": this.css('fontWeight'),
      "fontFamily": this.css('fontFamily'),
      "top": 0,
      "left": -1 * parseInt(width) + 'px',
      "position": 'absolute',
      "display": "inline-block",
      "width": width
    });
    
    return spanText.innerHeight() + 'px';

    };

    /**

    • Adjust the font-size of the text so it fits the container.
    • @param minSize Minimum font size?
    • @param maxSize Maximum font size?
    • @param truncate Truncate text after sizing to make sure it fits? */ $.fn.autoTextSize = function(minSize, maxSize, truncate) { var _self = this, _width = _self.innerWidth(), _textWidth = parseInt(_self.getTextWidth()), _fontSize = parseInt(_self.css('font-size'));

      while (_width < _textWidth || (maxSize && _fontSize > parseInt(maxSize))) { if (minSize && _fontSize <= parseInt(minSize)) break;

      _fontSize--; _self.css('font-size', _fontSize + 'px');

      _textWidth = parseInt(_self.getTextWidth()); }

      if (truncate) _self.autoTruncateText(); };

      /**

    • Function that truncates the text inside a container according to the
    • width and height of that container. In other words, makes it fit by chopping
    • off characters and adding '...'. */ $.fn.autoTruncateText = function() { var _self = this, _width = _self.outerWidth(), _textHeight = parseInt(_self.getTextHeight(_width)), _text = _self.text();

      // As long as the height of the text is higher than that // of the container, we'll keep removing a character. while (_textHeight > _self.outerHeight()) { _text = _text.slice(0,-1); _self.text(_text); _textHeight = parseInt(_self.getTextHeight(_width)); _truncated = true; }

      // When we actually truncated the text, we'll remove the last // 3 characters and replace it with '...'. if (!_truncated) return; _text = _text.slice(0, -3);

      // Make sure there is no dot or space right in front of '...'. var lastChar = _text[_text.length - 1]; if (lastChar == ' ' || lastChar == '.') _text = _text.slice(0, -1); _self.text(_text + '...'); }; })(jQuery);

11 votes

Autotruncate peut être réalisé en pure CSS en ajoutant deux règles : overflow : hidden " et " text-overflow : ellipsis ". Je sais que c'est très vieux, mais peut-être que quelqu'un en profitera :)

4voto

Christ Points 106

@Clovis Six Merci pour votre réponse. Elle s'est avérée très utile pour moi. Dommage que je ne puisse pas vous remercier plus qu'un simple vote vers le haut.

Note : Je dois remplacer "$J(" par "$(" pour que cela fonctionne avec ma configuration.

evendo, cela sort du cadre de cette question et n'est pas dans l'usage de SO, j'ai étendu votre code pour le faire fonctionner pour une boîte multi-ligne avec une hauteur maximale.

  /**
   * Adjust the font-size of the text so it fits the container
   *
   * support multi-line, based on css 'max-height'.
   * 
   * @param minSize     Minimum font size?
   * @param maxSize     Maximum font size?
   */
  $.fn.autoTextSize_UseMaxHeight = function(minSize, maxSize) {
    var _self = this,
        _width = _self.innerWidth(),
        _boxHeight = parseInt(_self.css('max-height')),
        _textHeight = parseInt(_self.getTextHeight(_width)),
        _fontSize = parseInt(_self.css('font-size'));

    while (_boxHeight < _textHeight || (maxSize && _fontSize > parseInt(maxSize))) {
      if (minSize && _fontSize <= parseInt(minSize)) break;

      _fontSize--;
      _self.css('font-size', _fontSize + 'px');

      _textHeight = parseInt(_self.getTextHeight(_width));
    }
  };

PS : Je sais que cela devrait être un commentaire, mais les commentaires ne me permettent pas de poster un code correctement.

4voto

tkahn Points 872

Aujourd'hui, j'ai créé un plugin jQuery appelé jQuery Responsive Headlines qui fait exactement ce que vous voulez : il ajuste la taille de la police d'un titre pour qu'elle tienne dans l'élément qui le contient (un div, le corps ou autre). Il y a quelques options intéressantes que vous pouvez définir pour personnaliser le comportement du plugin et j'ai également pris la précaution d'ajouter le support de la fonctionnalité Throttle/Debounce de Ben Altmans pour augmenter les performances et alléger la charge sur le navigateur/ordinateur lorsque l'utilisateur redimensionne la fenêtre. Dans son cas d'utilisation le plus simple, le code ressemblerait à ceci :

$('h1').responsiveHeadlines();

...qui transformerait tous les éléments h1 de la page en titres réactifs d'une ligne dont la taille serait adaptée à l'élément parent/conteneur.

Vous trouverez le code source et une description plus longue du plugin sur cette page GitHub .

Bonne chance !

0 votes

Merci beaucoup Monsieur. +1 !!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X