Filling div using letter-spacing
Asked Answered
V

6

10

The problem I'm having is filling a div with text using letter-spacing. The main issue is, I don't know the width of the div.

First I was thinking using, text-align= justify, but since that I've been running in the dark and got no clue to how to solve this. I'm guessing some scripting magic might do the trick.

An imgur link giving you an idea what I mean:

what I have versus what I want

<div id="container">
 <h1>Sample</h1>
 <p>Another even longer sample text</p>
</div>

Here is a link showcasing an example; JSfiddle.

Venitavenite answered 15/3, 2014 at 22:45 Comment(8)
At this point you can't technically call it letter-spacing anymore. It's more like text-align being something towards justify. letter-spacing does not mind the text it's surroundings. Text-alignment does. It is a good question tho :)Antiicer
possible duplicate of CSS text justify with letter spacingDraghound
With the current CSS Draft it will be very hard to get this to work. Even if you get it to work with weird combinations of styling it will likely not work in all browsers. If you have the facilities I would recommend solving this with JavaScript. Otherwise it will be a long run.Antiicer
Maybe this can be worth a look at: letteringjs.com or fittextjs.comBrouhaha
Here's a jQuery example: jsfiddle.net/DMw6Z. Won't post this as an answer, as you didn't ask specifically for a JavaScript solution. Try resize the screen too and see how it smoothly moves with the changing width.Antiicer
I'd suggest against doing this. It's jarring when the space between letters on one line is the same or larger than the space between words on the next...Huntress
@Huntress The jarring is no problem here. The spans will always abide by the rendered width of each letter, no matter what font or size you use. If you have concrete input I'm happy to fill in on that too :)Antiicer
I realised I hadn't written the right code in my answer. It is now fixed and the example fiddle also works on window resize.Craze
A
7

Based the comment of the poster it seems JavaScript is no problem. Here's a possible approach to solve the problem with jQuery:

JSFiddle 1

function dynamicSpacing(full_query, parent_element) {
    $(full_query).css('letter-spacing', 0);
    var content = $(full_query).html();
    var original = content;
    content = content.replace(/(\w|\s)/g, '<span>$1</span>');
    $(full_query).html(content);

    var letter_width = 0;
    var letters_count = 0;
    $(full_query + ' span').each(function() {
        letter_width += $(this).width();
        letters_count++;
    });

    var h1_width = $(parent_element).width();

    var spacing = (h1_width - letter_width) / (letters_count - 1);

    $(full_query).html(original);
    $(full_query).css('letter-spacing', spacing);
}

$(document).ready(function() {
    // Initial
    dynamicSpacing('#container h1', '#container');

    // Refresh
    $(window).resize(function() {
        dynamicSpacing('#container h1', '#container');
    });
});

Update

Small tweak for when the wrapper gets too small: JSFiddle 2

Antiicer answered 15/3, 2014 at 23:34 Comment(5)
To keep the text on one line I would add white-space: nowrap - jsfiddle.net/tJErk/4Brouhaha
This is what I'm after! Great job! I tried to adjust the script to also work on the p-tag but it's having some slight issues. As for resizing the screen, the script got surprisingly good response.Venitavenite
One issue I see is that the letter-spacing when the values are too negative it makes the text unreadable but that would be difficult to control I guess.Brouhaha
Here's a small fix for when it gets too small. Further tweaking I leave up to you Kai :P jsfiddle.net/DMw6Z/1Antiicer
@Allendar - Thanks to you, my app is taking shape! pictureVenitavenite
S
1

Another solution if you don't have to be semantic (because you will get many spans), I mean if you need only the visual result, is to use flexbox.

So you have your <div id="#myText">TEXT 1</div>

We need to get this:

<div id="#myText">
    <span>T</span>
    <span>E</span>
    <span>X</span>
    <span>T</span>
    <span>&nbsp;</span>
    <span>1</span>
</div>

So then you can apply CSS:

#myText {
   display: flex;
   flex-direction: row;
   justify-content: space-between;
}

In order to transform the text to span you can use jQuery or whatever. Here with jQuery:

var words = $('#myText').text().split("");
$('#myText').empty();
$.each(words, function(i, v) {
    if(v===' '){
        $('#myText').append('<span>&nbsp;</span>');
    } else {
        $('#myText').append($("<span>").text(v));
    }
});

For better results remove put letter-spacing: 0 into #myText so any extra spacing will be applied.

Scheers answered 25/10, 2016 at 17:45 Comment(0)
C
0

This is obviously evil, but since there is no straight forward way to do it with just css, you could do: demo

HTML:

<div>text</div>

CSS:

div, table {
    background: yellow;
}
table {
    width: 100%;
}
td {
    text-align: center;
}

JS:

var text = jQuery("div").text();
var table = jQuery("<table><tr></tr></table>").get(0);
var row = table.rows[0];
for (var i = 0; i < text.length; i++) {
    var cell = row.insertCell(-1);
    jQuery(cell).text(text[i]);
}
jQuery("div").replaceWith(table);
Councilman answered 15/3, 2014 at 23:13 Comment(0)
F
0

This may help:

function fill(target) {
    var elems = target.children();

    $.each(elems, function(i,e) {  

        var x = 1;
        var s = parseInt($(e).css('letter-spacing').replace('px',''));

        while(x == 1) {
            if($(e).width() <= target.width() - 10) {
                s++;
                $(e).css('letter-spacing', s+'px');
            } else {
                x = 0;
            }

        }
    });
}

fill($('#test'));

Note: If letter spacing is : 0 then you don't have to use replace method. Or you can add letter-spacing:1px; to your css file.

For avoiding overflow, always give minus number to parent element's height for correct work.

Fin answered 15/3, 2014 at 23:18 Comment(2)
Javascript not my good side. Anyone kind enough to post a fiddle or try if this works?Venitavenite
Working on Chrome. I do not have chance to test it on Safari.Fin
C
0

An other approach I wrote for this question Stretch text to fit width of div. It calculates and aplies letter-spacing so the text uses the whole available space in it's container on page load and on window resize :

DEMO

HTML :

<div id="container">
    <h1 class="stretch">Sample</h1>
    <p class="stretch">Another even longer sample text</p>
</div>

jQuery :

$.fn.strech_text = function(){
    var elmt          = $(this),
        cont_width    = elmt.width(),
        txt           = elmt.text(),
        one_line      = $('<span class="stretch_it">' + txt + '</span>'),
        nb_char       = elmt.text().length,
        spacing       = cont_width/nb_char,
        txt_width;

    elmt.html(one_line);
    txt_width = one_line.width();

    if (txt_width < cont_width){
        var  char_width     = txt_width/nb_char,
             ltr_spacing    = spacing - char_width + (spacing - char_width)/nb_char ; 

        one_line.css({'letter-spacing': ltr_spacing});
    } else {
        one_line.contents().unwrap();
        elmt.addClass('justify');
    }
};

$(document).ready(function () {
    $('.stretch').each(function(){
        $(this).strech_text();
    });
    $(window).resize(function () { 
        $('.stretch').each(function(){
            $(this).strech_text();
        });
    });
});

CSS :

body {
    padding: 130px;
}

#container {
    width: 100%;
    background: yellow;
}

.stretch_it{
    white-space: nowrap;
}
.justify{
    text-align:justify;
}
Craze answered 4/7, 2014 at 8:27 Comment(0)
F
0

No need for JavaScript

You can put &nbsp; between all letters inside words and &emsp; between words.

(Such text can be prepared using regular expressions for static HTML or dynamically on the backend.)

For line breaks, for example to have only one word per line, use &emsp;<br> between words.

Combine that with justify:

div {
    text-align: justify;
    text-align-last: justify;
    letter-spacing: -0.15em;
    width: 120px;
}
<div>
S&nbsp;o&nbsp;m&nbsp;e&nbsp;t&nbsp;h&nbsp;i&nbsp;n&nbsp;g&emsp;<br> l&nbsp;i&nbsp;k&nbsp;e&emsp;<br> t&nbsp;h&nbsp;i&nbsp;s&emsp;
</div>

<br>

<div>
S&nbsp;o&nbsp;m&nbsp;e&nbsp;t&nbsp;h&nbsp;i&nbsp;n&nbsp;g&emsp; l&nbsp;i&nbsp;k&nbsp;e&emsp; t&nbsp;h&nbsp;i&nbsp;s&emsp;
S&nbsp;o&nbsp;m&nbsp;e&nbsp;t&nbsp;h&nbsp;i&nbsp;n&nbsp;g&emsp; l&nbsp;i&nbsp;k&nbsp;e&emsp; t&nbsp;h&nbsp;i&nbsp;s&emsp;
S&nbsp;o&nbsp;m&nbsp;e&nbsp;t&nbsp;h&nbsp;i&nbsp;n&nbsp;g&emsp; l&nbsp;i&nbsp;k&nbsp;e&emsp; t&nbsp;h&nbsp;i&nbsp;s&emsp;
</div>

Result: screenshot

Forme answered 23/8 at 11:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.