2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HTMLで要素の幅に合わせて疑似的にフォントサイズを変更(JS使用)

Posted at

初めに

HTMLで、要素の中に文字を入れたいが、要素をはみ出てしまう場合に自動でフォントの大きさを要素内に収まるように調節してくれるものを探していたのですが、私が求めていたものは見つからなかったので、自作しました。
(もしかしたら私が見つけられてないだけでCSSにあるのかもしれませんが...)

コード

HTML全体は以下のようになっております。
CSSもJavascriptもHTML内に書きましたので、分けたい方は各自分けてください。

FontChange_index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Example</title>
    <style>

        .TargetDiv {
            position: relative;
            width: auto;
            height: 30px;
            margin: 10px 0px;
            background-color: aquamarine;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .TargetText {
            position: absolute;
            margin: 0;
            font-size: 100%;
            background-color: blue;
            color: white;
            transform-origin: 0% 50%;
        }

    </style>
</head>

<body onload="FontSizeChange()">

    <div class="TargetDiv" style="width: 130px;">
        <p class="TargetText">おはようございます</p>
    </div>

    <div class="TargetDiv" style="width: 300px;">
        <p class="TargetText">こんにちは</p>
    </div>

    <div class="TargetDiv" style="width: 240px;">
        <p class="TargetText">こんばんは!!!!!!!</p>
    </div>
    
    <input id="InputText">

    <button onclick="InputText()">確定</button>
    
    <script>

        let TargetParents = document.querySelectorAll(".TargetDiv");
        let TargetTexts = document.querySelectorAll(".TargetText");
        const TargetElements = [];

        // 全ての対象の要素・テキストの情報を配列に代入
        for (let i = 0; i < TargetParents.length; i++) {

            TargetElements[i] = [TargetParents[i], TargetTexts[i]];

        }
       
        /**
         * 入力した文字を代入させる関数
         */
        function InputText() {

            for (TargetElement of TargetElements) {

                //全ての対象のテキストに入力した文字を代入
                TargetElement[1].innerHTML = document.getElementById("InputText").value;

            }

            // ボタンを押したときに実行
            FontSizeChange();

        }
        
        /**
         * フォントサイズを調節する関数 今回のメインはこれ
         */
        function FontSizeChange() {

            for (TargetElement of TargetElements) {
                
                // 親のDiv要素の横の長さと、その中のテキストの中の割合
                // 親のDiv / テキスト
                const SizeCheck = TargetElement[0].offsetWidth / TargetElement[1].offsetWidth;
                // 元の大きさと、割合の大きさを比較し、小さい方の値を代入
                const TextWidthScale = Math.min(1, SizeCheck);
                // テキストの拡大率を変更
                TargetElement[1].style.scale = TextWidthScale;

                // テキストがはみ出た場合に実行される部分
                if (TextWidthScale < 1) {

                    console.log("Text Over");

                }

            }

        }

    </script>
</body>
</html>

実行結果

このHTMLを開くとこのようになっております。
1.png
分かりやすいように、親要素には水色、フォントには青色を指定しています。

今回の場合だと、「おはようございます」がそのままのサイズだと要素からはみ出てしまうため、少しですが小さくなっているのが分かります。


では、ここに少し長めの文字を入れてみましょう。
結果は以下のようになりました。
2.png
「これからよろしくお願いいたします。」と入れてみました。
しっかりと対応しているのが分かります。

解説

簡単に仕組みを説明します。(CSS、文字を代入する部分は割愛します)

HTML

今回の場合、対応させたい文字には以下の記述方法で書きます。

<div class="TargetDiv" style="width: 親要素の横幅;">
    <p class="TargetText">テキスト</p>
</div>

このようにclass属性を付けてあげることで、Javascriptで要素を取得できるようにします。

Javascript

次に、Javascriptで要素を取得し、TargetElementsに代入します。

let TargetParents = document.querySelectorAll(".TargetDiv");
let TargetTexts = document.querySelectorAll(".TargetText");
const TargetElements = [];

// 全ての対象の要素・テキストの情報を配列に代入
for (let i = 0; i < TargetParents.length; i++) {

    TargetElements[i] = [TargetParents[i], TargetTexts[i]];

}

for文を使い、TargetElements[i]内に、
[i番目の親要素の情報, i番目のテキストの情報]
を代入します。

そして、この部分でフォントサイズを変更しています。

for (TargetElement of TargetElements) {
                
    // 親のDiv要素の横の長さと、その中のテキストの中の割合
    // 親のDiv / テキスト
    const SizeCheck = TargetElement[0].offsetWidth / TargetElement[1].offsetWidth;
    // 元の大きさと、割合の大きさを比較し、小さい方の値を代入
    const TextWidthScale = Math.min(1, SizeCheck);
    // テキストの拡大率を変更
    TargetElement[1].style.scale = TextWidthScale;

    // ここから先はメインと関係ないので省略     

}

for文でそれぞれの親要素とテキストを個別に処理していきます。

ここで重要なのは、
「直接フォントサイズを変更している」のではなく、
「フォントの拡大率を変更させて疑似的にフォントサイズが変わったように見せている」
というところです。

CSSのfont-size指定だとめんどくさそうだったので、代わりのものはないかと考えたときにこの方法を思いつきました。


まず、それぞれの親とテキストの横幅を比較し、
テキストの横幅を1としたときの親要素の横幅の割合を代入します。

// 親のDiv / テキスト
const SizeCheck = TargetElement[0].offsetWidth / TargetElement[1].offsetWidth;

こうすることで、テキストの横幅が親要素を超えた際、SizeCheckの値が1を下回るのが分かると思います。

そして、元の大きさの割合(1)と、SizeCheckを比較し、小さい方の値をTextWidthScaleに代入します。

// 元の大きさと、割合の大きさを比較し、小さい方の値を代入
const TextWidthScale = Math.min(1, SizeCheck);

これで、テキストの横幅を調節するための拡大率が求まったので、あとはその拡大率が適応されるように記述するだけです。

// テキストの拡大率を変更
TargetElement[1].style.scale = TextWidthScale;

解説は以上です。
あとは各自使いたいように改良してください。

最後に

私の知識不足により、誤った情報を書いてしまったり、今回初めてQiitaで記事を書いたので、どこか説明不足があるかもしれませんが、
大目に見ていただけるとありがたいです。m(_ _)m

ご閲覧ありがとうございました。

2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?