[WordPress] 漫画っぽいふきだし

CSS
スポンサーリンク
こんにちは。 雑食会社員🐼くま子です
いえーい!
スポンサーリンク

背景

私のブログは文字ばかりで読みにくいなぁ
可愛くて面白い絵を挿絵として入れたいな

と思ったので、漫画っぽいふきだしを簡単に差し込める仕組みをつくりました。
(絵が下手なので漫画は書けないから、あらかじめ絵を用意して、やつら🍙に喋ってもらうことにした)

CSSだけでつくるのはやめた

最近ブログ界隈では吹き出しが流行っているようで、CSSで作った吹き出しで会話をさせるサイトをよく見かけます。

私がお世話になっているWordPressテンプレートのSimplicityCocoonでも、簡単に吹き出しが使えるようになっています。

CSSでつくれるふきだし

しかし…

これだと漫画っぽい多様な形の吹き出しが作れない

(吹き出しを紹介する記事なので、さっきから乱用しています。)

↑のように、

  • キャラクターに表情をつけられる
  • 吹き出し内の色も変えつついろいろな形の吹き出しを使える

仕組み を作ることにしました。

方法

CSSとSVGを使うことにしたよ

結構思考錯誤してJS使ったりすることも試したのですが、使わなくても実現できそうだったので、結局やめました。

SVGにしたのは、吹き出し内の文字の長さによって拡大縮小しても線の太さや画像の荒さが変わらないようにしたいという、エンジニアのどうでもいいこだわりです。

ふきだし

まずはふきだしを用意。

SVGを用意

これ↓を利用したときの例です。

横からにょろり – ふきだし素材専門サイト「フキダシデザイン」
デザイン向けふきだし素材を配布するサイト

可愛いからそのままいただきました。

※ 現在はSVGでDLできるようなので、以下の書き出しは不要。


AI形式なので、イラストレーターにて下記の設定でSVGに書き出します。

  • スタイル : 「内部CSS」
    • のちに削除しやすいように
  • オブジェクトID : 最小
    • ファイルサイズ抑えるために
  • 小数点以下の桁数 : 1
    • ファイルサイズ(略)
  • 「縮小」にチェック
    • ファイルサイズ(略)
  • 「レスポンシブ」にチェック

SVGを編集

以下を削除
– 1,2行目のコメント
<svg>タグ
+ ver
+ id
+ x
+ y
+ style
+ xml:space
<style>

以下を追加
* <svg>
preserveAspectRatio="none"
* <path>
vector-effect="non-scaling-stroke"

after
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 552 253">
    <path vector-effect="non-scaling-stroke" d="M411 18c-40-8-89-13-150-13s-109 5-149 13C53 29 5 66 5 126s48 98 107 109a762 762 0 0 0 172 13c50-1 92-6 127-13 27-5 46-12 65-28 3-2 11-8 20-6l20 5c20 2 31-12 31-12-1-2-13 1-22-7-6-6-11-14-13-20-1-2 1-9 1-11a103 103 0 0 0 4-30c0-60-47-97-106-108z"/>
</svg>

viewBox削除しちゃったら全然うまく動かなくてハマった

キャラクター

新しいアイコンを利用した「吹き出しデモ」を手っ取り早く登録する方法
v0.7.0より、デフォルトの吹き出しアイコンが変わりました。ただ、以前のバージョン既に使っている方は、新しいアイコンを使用したデモ吹き出しは登録されません。新しいアイコンを利用する場合は、以下からダウンロードして登録する必要があります。た...

よくみるこういうふきだしでは満足しない私は、
もっとまめきちまめこ、みたいな勢いと面白さを目指します。

それには面白い絵が欠かせないと思うのですが、
絵は全く得意でないので、顔と体とそれぞれ何パターンか用意して、組み合わせて使うことにしました。

絵を描く

絵が苦手すぎるので(なのに、使い方もわからずイラストレーターを持っている宝の持ち腐れ)、
ペンツールでぽちぽちと点を打って、それらを繋げて線にして、書きました。
ペンタブなんか使ってもうまく書けないので、ひたすらマウスでぽちぽちと書きました。

SVGに書き出す

顔と体をそれぞれ別々にして、SVGに書き出します。

以下の二点がポイント。

  • 余白を含めたアートボードごと書き出す
  • 「レスポンシブ」のチェックを外す
  • あとで顔と体を合体させるため

書き出したSVGを編集する必要性はなし。
タイトルが不要なくらい?

ほんとはふきだしと同じくvector-effect="non-scaling-stroke"を追加したいけど、
絵だとパスが多すぎていちいち追加するの大変だし、
線の太さが変わってしまうと絵が変わってしまって面倒かなぁ?と思って、
特に何もしてない。笑

HTML

この漫画っぽいふきだしシステムを、わたしは「わんごま」と名付けました。
なのでcssのクラス名はonegomaです。

ださい名前だ

ふきだしの種類、使う顔・体、セリフをHTMLで記載します。

<div class="onegoma {$side}">
<div class="balloon" data-frame="{$frame}" data-type="{$type}">{$content}
{$balloon}</div>
<div class="character"><object data="{$body}" type="image/svg+xml" width="300" height="150"></object>
<object class="face" data="{$face}" type="image/svg+xml" width="300" height="150"></object></div>
</div>
{$変数}指定する内容
{$side}キャラクターの位置CSSのクラス名
{$frame}ふきだしの形CSSのクラス名
{$type}ふきだしのデザインCSSのクラス名
{$content}本文思うがままに書け
{$balloon}ふきだしのSVGSVGファイルの中身をそのまま書き出す(...)
{$body}キャラクターの体SVGファイルのURL
{$body}キャラクターの顔SVGファイルのURL

ふきだしは、線や塗りつぶしの色などをCSSから編集できるように、SVGをそのまま書き出します。
顔や体はとくにいじる予定がないので、Objectとして読み込み。

「CSSのクラス名」の部分は、後述のCSSに記載したクラス名を書く。

CSS

素材は用意できたので、あとはうまく並べれば完成!

SCSS

これを機会にSCSSを使ってみました。

.onegoma {
    --balloon-padding: 8%;
    --balloon-padding-tail: 10%;
    --character-margin-tail: -5%;
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flex;
    display: -o-flex;
    -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
    -ms-flex-direction: row;
    flex-direction: row;
    -webkit-flex-wrap: nowrap;
    -ms-flex-wrap: nowrap;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    &.left {
        -webkit-box-orient: horizontal;
        -webkit-box-direction: reverse;
        -ms-flex-direction: row-reverse;
        flex-direction: row-reverse;
        .balloon {
            padding-right: var(--balloon-padding);
            padding-left: var(--balloon-padding-tail);
        }
        .character {
            margin-right: var(--character-margin-tail);
            margin-left: 0;
        }
        svg, object {
            transform: scale(-1,1);
        }
    }
    &.bottom {
        -webkit-box-orient: vertical;
        -ms-flex-direction: column;
        flex-direction: column;
        .character {
            margin: 0;
            margin-top: var(--character-margin-tail);
        }
    }
    .balloon {
        width: auto;
        margin: 10px;
        padding: var(--balloon-padding);
        padding-right: var(--balloon-padding-tail);
        position: relative;
        z-index: 2;
        svg {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0px;
            top: 0px;
            z-index: -1;
            &> * {
                fill: transparent;
                stroke: black;
                stroke-width: 2px;
            }
        }
        &[data-frame='boom'] {
            padding: 15%;
        }
        &[data-type='blue'] {
            svg>* {
                fill: skyblue;
                stroke: transparent;
            }
        }
        &[data-type='gold'] {
            svg>* {
                fill: gold;
            }
        }
    }
    .character {
        width: 25%;
        height: 25%;
        max-width: 200px;
        max-height: 200px;
        margin-left: var(--character-margin-tail);
        position: relative;
        text-align: center;
        object {
            width: 100%;
            height: 100%;
            box-shadow: none;
            &.face {
                left: 0px;
                top: 0px;
                position: absolute;
            }
        }
    }
}
  • ふきだしの画像の上に文字を表示するために、balloonクラスとSVGにz-indexを指定
  • キャラクターの画像を正方形で書き出していて余白が目立ったので、ネガティブマージンでちょっと寄せてみた

ショートコードを作る

もう概ね完成したのでいいのですが、
毎回HTMLを描くのも面倒なので、ショートコードを作りました。
function onegomaCode($atts, $content = null) {
    $url = "https://blog.kuromusubi.com/wp-content/plugins/onegoma";
    $path = dirname(__FILE__);

    if (is_array($atts)) {
        $atts = array_filter($atts, "strlen");

        // ファイルが見つからない場合は初期値を使う
        foreach($atts as $k => $v) {
            if (in_array($k, array('type', 'side'))) continue;

            $tmparr = explode(',', $v);
            foreach($tmparr as $i => $a) {
                if (!count(glob($path . "/image/{*,*/*}/{$a}.svg", GLOB_BRACE)))
                    unset($tmparr[$i]);
            }
            if (count($tmparr))
                $atts[$k] = implode(',', $tmparr);
            else
                unset($atts[$k]);
        }
    }

    extract(shortcode_atts(array(
        'frame' => 'normal',
        'type' => 'normal',
        'body' => 'normal',
        'face' => 'normal',
        'accessory' => '',
        'side' => 'right'
    ), $atts));

    $balloon = file_get_contents($path . "/image/balloon/{$frame}.svg");
    $body = $url . "/image/character/body/{$body}.svg";
    $face = $url . "/image/character/face/{$face}.svg";
    $accessory_html = "";
    if ($accessory != "")
        foreach(explode(',', $accessory) as $a) {
            $accessory_html .= "<object type=\"image/svg+xml\" data=\"". $url . "/image/character/accessory/{$a}.svg\" class=\"accessory\"></object>";
        }

    return <<<TXT
    <div class="onegoma {$side}">
        <div class="balloon" data-frame="{$frame}" data-type="{$type}">
            {$content}
            {$balloon}
        </div>
        <div class="character">
            <object type="image/svg+xml" data="{$body}"></object>
            <object type="image/svg+xml" data="{$face}" class="face"></object>
            {$accessory_html}
        </div>
    </div>
TXT;
}
add_shortcode('onegoma', 'onegomaCode');

svgをあらかじめ階層に配置しておいて、引数の文字列のものを取ってきます。
万が一指定した画像がないときに首なしにならないように、画像がない場合はデフォルト値を使うようにしました。

コメント