この記事は Goodpatch Advent Calendar 2021、10日目の記事です。
はじめに
こんにちは。株式会社グッドパッチ でエンジニアインターン中のちげと申します。趣味でデザインをやっている寿司とすき焼きが好きなフロントエンドエンジニアです。現在、Strap というオンラインホワイトボードサービスの開発に携わっています。
Strap を開発しているチーム(以下: Strapチーム)では、STUDIO というサービスを使用して、ランディングページ(LP)を作成しています。私が過去に STUDIO を少し触っていたこともあり、Strap 自体の開発だけでなく、STUDIO のサイト更新タスクにアサインされることもありました。
STUDIOとは
STUDIO は LP に必要なほとんどの機能を、Web 上の GUI で作る事ができる、ノーコードWebサイト作成ツールです。CMS やフォーム等も作ることができ、デザイナーやエンジニア以外の人でも更新が容易です。自社で LP を持つよりも、非常に楽に管理できるサービスだと思います。
しかし、もちろんですが、HTML/CSS/JavaScript をバリバリコーディングするよりも、デザインやインタラクション、実装の自由度は下がります。そのため「CSS ならこのプロパティ入れるだけで済むのに、その設定はないのか…」や「JS が書けたらなぁ」などというお気持ちはどうしても出てきてしまいます。
「業務をすすめる上で欲しくなった仕様が STUDIO でうまく動かないかもしれない」となった時、皆さんならどう対応されるでしょうか。本記事では「頑張れば STUDIO で出来たよ!」というちょっとトリッキーな工夫が2点あるので、ご紹介したいと思います。
ハック術の実例紹介🔧
ハック術① バツボタンで消えるリンクバナーを作る
背景
ある時、Strapチームのデザイナーさんから相談を受けました。
「ちげくん、サイトにスクロール追従するリンクバナーを出したいんだけど、そのバナーをバツボタンで消したいんだよね。STUDIO でできるかなぁ?」
イベントページへのリンクバナーを、トップページに表示したいというものでした。挿入する画像はイベント情報の OGP です。リンクバナーを表示するのはイベント期間中の一時的なもので、イベントが終わればリンクバナー自体を非表示にします。
また、今後イベントが開催された時に、画像とリンクを変えたバージョンのリンクバナーを同様に出す予定でした。そのため更新コストの見積もりも必要でした。幸い、イベントの開催頻度がそれほど高くなく、更新したい画像サイズも統一されていました。画像のデザインはテンプレ化して属人性を解消しています。更新時の変更点が少ないため、エンジニア側で更新できれば問題ないと判断しました。
このリンクバナーは本記事で紹介するハック術を使って実際に Strap の LP で使っています。イベントがないと表示されないので、Twitterの告知などからイベントがあるときにアクセスしてもらえれば、表示されているはずです。もちろんイベントの参加もお待ちしています!(◦ˉ ˘ ˉ◦)
仕様
仕様は以下のとおりです。
- ページ右下固定でスクロールに追従する (fixed 要素)
- クリックするとリンク先へ飛ぶ(aタグ)
- バツボタンがついており、クリックするとバナーが消える
- 画像が挿入できる
デモ↓↓↓(バナーを消してしまった後は、Rerunボタンで復活します。)
See the Pen floating banner 2 by Chige (@Chige) on CodePen.
実装方法⛏
結論:埋め込みコード機能を使って、HTML/CSS を埋め込む
STUDIO には、Youtube の動画や Twitter の Iframe を埋め込むための埋め込みコード機能が提供されています。この埋め込みコードに生の HTML/CSS を書いちゃえ!という発想です。
JavaScript は XSS 対策されているため動きませんが、今回のケースでは HTML/CSS だけで実装可能です。
HTML のチェックボックス <input type="checkbox">
を使えば、JavaScript を使わずともスタイルのトグルスイッチングが可能です。CSSの input:checked
擬似クラスセレクターをつかうことで実現できます。
<div class="hidden_box"> <input type="checkbox" id="label1"/> <label for="label1">×</label> <a href="https://www.google.com/" target="_blank" class="hidden_show"> <img class="banner-img" width="400" height="200" src="image.png"> </a> </div>
/* バナーを表示する */ .hidden_box .hidden_show { opacity: 1; pointer-events: auto; } /* チェックボックスは見えなくする */ .hidden_box input { display: none; } /* クリックで非表示 */ .hidden_box input:checked ~ .hidden_show, .hidden_box input:checked ~ label{ opacity: 0; cursor: auto; pointer-events: none; }
手順
box
を出し、配置を固定にする。左側メニュー > 追加 > Box > Iframe
から Iframe を追加し、box
の中に Iframe を入れる。- Iframe を選択し、開いた右側メニュー内の "タイプ" を Custom にする
バナーのHTML, CSSを書く。以下「バナーのHTML, CSSについて」を参照。 JavaScript (scriptタグ) は書くことができないので注意。
遷移先リンクと画像リンク、画像縦横比を書き換える。
"埋め込みコード" に貼り付け。
boxの横幅と縦幅を共に auto にする。
Iframe の横幅と縦幅を共に 100% にする
重ね順を1以上にし、boxの固定位置をこのよう↓に絶対位置で指定する。
バナーのHTML, CSSについて
以下のコードを "埋め込みコード" へコピペする。
<style> .hidden_box { position: relative; width: min-content; margin: 0; padding-top: 14px; padding-right: 12px; } /*バツボタン*/ .hidden_box label { display: block; position: absolute; width: 24px; height: 24px; top: 0px; right: 0px; margin: auto; text-align: center; line-height: 30px; box-shadow: 0px 8px 24px -8px rgba(0, 13, 147, 0.32); cursor :pointer; transition: 0.3s; z-index:1; background: #fff; border-radius: 100%; } .hidden_box label:hover { background: #fff; } .hidden_box .banner-img { display: block; } /*バナー装飾*/ .hidden_box .hidden_show { display: block; width: min-content; height: auto; background: #fff; cursor:pointer; border: 1px solid #EAECF1; border-radius: 8px; overflow: hidden; box-shadow: 0px 21.248px 42.496px -21.248px rgba(0, 13, 147, 0.16); transition: 0.3s; /*表示する*/ opacity: 1; pointer-events: auto; } .hidden_box .hidden_show img { transition: 0.3s; } /*バナーホバー時*/ .hidden_box .hidden_show:hover img { opacity: 0.85; } /*チェックは見えなくする*/ .hidden_box input { display: none; } /*クリックで非表示*/ .hidden_box input:checked ~ .hidden_show, .hidden_box input:checked ~ label{ opacity: 0; cursor: auto; pointer-events: none; } </style> <div class="hidden_box"> <input type="checkbox" id="label1"/> <label for="label1">×</label> <!-- ここの遷移リンクを変える --> <a href="https://www.google.com/" target="_blank" class="hidden_show"> <!-- ここの画像リンクを変える --> <img class="banner-img" width="400" height="200" src="image.png"> </a> </div>
注意事項
STUDIOの "埋め込みコード" 内のテキストボックスが読みにくいので、改行して整形したくなりますよね。
しかし改行して整形すると、勝手に <br>
が挿入されてうまくスタイルが適応されない場合があります。
ハック術② 複数画像の登場アニメーションを個別に設定して、かつレスポンシブ対応させる
背景
ある時、StrapチームのデザイナーさんとイベントLPサイトのアニメーションについて話していました。
「ちげくん、ページ表示時に、図形を個別にアニメーションさせたいんだけど、いい感じにできないんだよねぇ」 「そのへん得意なんでやりますよ!」
最終的に完成したアニメーションがこちらです↓↓↓。
カラフルな図形(画像)が中央に向かってふわっと登場するアニメーションです。一枚の画像ではなく、複数の画像を個別でアニメーションさせている事がわかります。実際にアニメーションが動いている様子は こちら (Strap User Meetup) からご覧いただけます。こちらも本記事で紹介するハックを使って実装されています。
STUDIO には &appear
コンディションという機能があり、ページ表示時に再生されるアニメーションは簡単に作れます。 しかし、図形を個別にアニメーションさせたいというニーズを満たすには、レスポンシブ対応という点で少々工夫が必要でした。
仕様
- サイト初期読み込み時に動く登場アニメーション
- 背景の個々のシェイプは、登場時間のズレ(delay)を利用した登場表示
- 画像は読み込み時間短縮のため、シェイプを個別に書き出した最小限サイズを使いたい。
- レスポンシブ対応
- スマホ用の画像を別で用意せずにPC版と同じ画像で動くようにしたい
最初に考えた実装方法🤔
⚠️ この方法はボツになったため、結論が先に知りたい方は 採用した実装方法 へどうぞ。
div
要素を置き、その中の複数の画像も絶対位置指定 position:absolute;
にしました。
そして top: 〇px; left: 〇px;
となるようにSTUDIOで設定しました。
以下のような DOM です。
<div class="wrapper"> <div class="image posi-1"></div> <div class="image posi-2"></div> <div class="image posi-3"></div> </div>
.wrapper { position: relative; } .image { position:absolute; background-size: contain; background-position: center; width: 400px; height: 250px; } .posi-1 { top: -22px; /*上に平行移動したい分*/ left: 470px; /*左に平行移動したい分*/ background-image: url(image.png); } .posi-2 { /* ~~~ image-1と同様 ~~~ */ } .posi-3 { /* ~~~ image-1と同様 ~~~ */ }
しかしこの手法では問題がありました。STUDIO では、div
要素に常に max-width: 100%;
が入ってるようで、画面幅が小さくなった時に、画像がはみ出さないのです。left
プロパティで画面の左端に貼り付いているので、画面幅を変えた時に、画面端と同じ動きで位置がどんどんズレていってしまいます。スマホ表示では画像たちがズレすぎて「どこ行くね〜ん!」といった感じです。
max-width: unset;
を強制したい!と強く思いましたが、ノーコードなのでできません。
絶対位置指定ではどうしてもこの問題を解消できませんでした。
採用した実装方法⛏
結論:画像を position:absolute;
にせず、ただの margin
で上下左右移動させる
以下のような DOM を STUDIO で作ります。
<div class="wrapper"> <div class="image posi-1"></div> <div class="image posi-2"></div> <div class="image posi-3"></div> </div>
.wrapper { position: absolute; top: 0; left: 0; width: 100%; } .image { background-size: contain; background-position: center; width: 100%; height: 250px; } .posi-1 { margin-top: -22px; /*上に平行移動したい分*/ margin-bottom: 22px; margin-left: 470px; /*左に平行移動したい分*/ margin-right: -470px; background-image: url(image.png); } .posi-2 { /* ~~~ image-1と同様 ~~~ */ } .posi-3 { /* ~~~ image-1と同様 ~~~ */ }
このDOMに、アニメーション用の transform
プロパティがつくようなイメージです。
手順
- 以下のようなDOM構造を作る。第三段目が動かしたいオブジェクト(画像)。
<div> #white-figure
の配置を絶対位置に、横幅を100%にする。これが階層で一番上のBoxになる。
- 二段目の
div
は、配置を相対位置に、横幅と高さを固定ピクセル値にする
CSSでいうcontainer
の役割を担う。
上揃えにして、上に位置する画像から順番に設定していく。
- 画像サイズを
contain
にする
- 横幅を 100% にする。(
container
と同じ) - 高さをピクセル指定にして、調整することで画像の大きさを決める。
- 画像サイズを
contain
からpixel
に戻して固定値にする。
ここで固定値にするのは、画面横幅が小さくなった時に画像が小さくならないようにするためです。 - 相対座標にして、左側マージン(または右側マージン)だけを使って表示したい位置へズラし、図形の表示位置を決定する。
- 左側マージンを増やしたら、左側マージンの2分の1の値を、両側マージンへ設定する。上下のマージンも同様。左側マージンと右側マージンを同時に編集するのが難しいので、このようなやり方が良いと思います。
- 画像サイズを
4.と同じ設定を順番に設定。
構造上、後から上側を編集すると、それより下側が崩れるので注意。
- 全ての画像が設定し終わったら、
&appear
をクリックして、モーションをいじる。
モーションは、transform
プロパティのtranslate
の移動設定で行います。図形の配置にtransform
を使わず、マージンを使ったので、モーションの設定値は独立しています。
そのため、後からアニメーションの変更もやりやすいですし、位置だけ変えたい場合も楽です。それがこの方法のメリットですね。
これで画面端に来たときに、図形が画面外へはみ出てくれるようになりました。というか、最初からすでにはみ出ている状態ですね。
より高度なハック
本記事には JavaScript は登場しませんでした。 もし、STUDIO で「どうしても JS が書きたい!」という方は以下の記事を参考にされると良いと思います。 Google Tag Manager(GTM)を使用しており、GTM 側で記述した JavaScript を STUDIO へ埋め込んでいます。
上記記事の方法を採用するにあたって注意すべき点として、GTM 内の JavaScript を管理・運用するコストが発生する点が挙げられます。 Strapチーム内では「STUDIO の良さは手軽にそこそこのページが作れるところ。そこまでこだわりたくなったとか、要件が大きくなったタイミングなら自前で構築する検討も必要そう」という話も出ました。すこしハック感が強すぎて、標準運用にはしたくない思いがありました。これはお気持ちの問題でもあるので、人によって変わる部分だと思います。
そのため、本記事は、STUDIO の機能の中で 実装するには?という視点で STUDIO ハックの実例をご紹介しました。
まとめ
STUDIO 結構色々できる。
本記事では、業務で実際に使った、STUDIO のトリッキーな工夫についてご紹介しました。アイデア次第で意外となんとかなるものです。
……でもやっぱり、STUDIO の各 Box 要素にテキストエリアがついてて、CSS を上書きできるようになったらいいなぁとも思っています……。それはそれで管理が地獄になりそうというのはあるんですが……。
今後も STUDIO はアップデートされていくでしょうし、こんなトリッキーなハックを行わずとも、きれいなノーコードで実現できるといいですね。STUDIO 実装チーム頑張ってください。応援してます!
よい STUDIO ライフを……
おわりに
グッドパッチではチームメンバーと職種を超えてコラボレーションしながら開発していただける仲間を募集しています。 カジュアル面談からでもぜひご応募ください。
デザイナーの方はこちら