20200205のHTMLに関する記事は12件です。

htmlとcssの雛形

自分用のメモです.

最初のページ

home.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="home.css">
  </head>

  <body>
    <h2 id="home_title">機能一覧</h2>
    <form>
        <button class="btn-flat-logo">機能1</button>
    </form>
    <form>
        <button class="btn-flat-logo">機能2</button>
    </form>

  </body>
</html>

home.css

h2#home_title {
    color: #505050;/*文字色*/
    padding: 0.5em;/*文字周りの余白*/
    display: inline-block;/*おまじない*/
    line-height: 1.3;/*行高*/
    background: #dbebf8;/*背景色*/
    vertical-align: middle;
    border-radius: 25px 0px 0px 25px;/*左側の角を丸く*/
}

h2#home_title:before {
    content: '●';
    color: white;
    margin-right: 8px;
}

.btn-flat-logo {
    position: relative;
    display: inline-block;
    font-weight: bold;
    font-size: 1.0em;
    padding: 10px 30px;
    margin: 10px 30px;
    text-decoration: none;
    color: #FFF;
    background: #00bcd4;
    transition: .2s;
    border-radius: 25px 25px 25px 25px;
}

.btn-flat-logo:hover {
    background: #1ec7bb;
}

機能1の入力フォーム

func1.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="func1.css">
  </head>

  <body>
    <h2 id="func1_title">機能1</h2>
    <div class="box26">
      <span class="box-title">機能説明</span>
      <p>
        機能1では製品とその製品情報を指定することで,データベース中から指定した情報を検索しデータを整形して出力する.
      </p>
    </div>

    <table>
        <p class="form-items">製品名</p>
      <tr>
        <td><input class="textarea" type="text"></td>
      </tr>
    </table>

    <div>
      <a class="form-items">詳細設定</a>
      <button class="btn-change"></button>
    </div>
    <table>
      <tr>
        <td><input class="textarea" type="tel"></td>
        <td><button class="btn-change"></button></td>
      </tr>
      <tr>
        <td><input class="textarea" type="tel"></td>
        <td><button class="btn-change"></button></td>
      </tr>
      <tr>
        <td><input class="textarea" type="tel"></td>
        <td><button class="btn-change"></button></td>
      </tr>
    </table>

    <button id="button-search" class="simple_square_btn6">
      検索
    </button>
    <div>

    </div>
    <button id="button-back" class="btn-open">
      戻る
    </button>

  </body>
</html>

func1.css

body {
    font-family: "Avenir Next";
}

h2#func1_title:first-letter {
    font-size: 1.5em;
    color: #7172ac;
}

.box26 {
    position: relative;
    margin: 2em 0;
    padding: 1em 1em;
    width: 20%;
    border: solid 3px #95ccff;
    border-radius: 8px;
}
.box26 .box-title {
    position: absolute;
    display: inline-block;
    top: -13px;
    left: 10px;
    padding: 0 9px;
    line-height: 1;
    font-size: 18px;
    background: #FFF;
    color: #95ccff;
    font-weight: bold;
}
.box26 p {
    font-size: 12px;
    margin: 0; 
    padding: 0;
}

.textarea {
    /* width: 50%; 親要素いっぱい広げる */
    padding: 10px 15px; /*ボックスを大きくする*/
    font-size: 16px;
    border-radius: 3px; /*ボックス角の丸み*/
    border: 2px solid #ddd; /*枠線*/
    box-sizing: border-box; /*横幅の解釈をpadding, borderまでとする*/
}

table {
    border-collapse: separate;
    border-spacing: 10px;
}

.form-items {
    color: #2b546a;
    font-weight: bold;
    margin: 0;  
}

.form-items:before {
    content: '●';
    color: #2b546a;
    margin-right: 8px;
}


.btn-change {
    display: inline-block;
    position: relative;
    box-sizing: border-box;
    text-decoration: none;
    width: 30px;
    height: 30px;
    padding: 5px;
    border-radius: 50%;
    text-align: center;
    font-weight: bold;
    box-shadow: inset 0 2px 0px rgba(255, 255, 255, 0.25), inset 0 -2px 0px rgba(0, 0, 0, 0.18);
    transition: .2s;
}

.btn-change:hover {
    box-shadow: none;
}

.btn-change:active {
    -webkit-transform: translateY(1px);
    transform: translateY(1px);
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.35);
    border-bottom: none;
}

.center-obj {
    text-align: center;
}

.simple_square_btn6 {
    left: 30px;
    display: block;
    position: relative;
    width: 160px;
    padding: 0.8em;
    text-align: center;
    text-decoration: none;
    color: white;
    background: #0bc8b6;
    border-radius: 30px;
    -webkit-backface-visibility: hidden; 
    -moz-backface-visibility: hidden;
    backface-visibility: hidden;
    font-weight: bold;
    font-size: 12px;
}
.simple_square_btn6:hover {
    cursor: pointer;
    text-decoration: none;
    -webkit-animation: simple_square_btn6 0.5s both;
    -moz-animation: simple_square_btn6 0.5s both;
    animation: simple_square_btn6 0.5s both;
}
@-webkit-keyframes simple_square_btn6 {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
  100% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
  }
}
@-moz-keyframes simple_square_btn6 {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
  100% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
  }
}
@keyframes simple_square_btn6 {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
  }
  100% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
  }
}

.btn-open {
    display: inline-block;
    top: 50px;
    /* left: 200px; */
    left: 0;
    width: 50px;
    height: 35px;
    text-align: center;
    background-color: #9ec34b;
    font-size: 10px;
    border-radius: 10px;
    color: #FFF;
    text-decoration: none;
    font-weight: bold;
    border: 2px solid #9ec34b;
    position: relative;
    overflow: hidden;
    z-index: 1;
}

.btn-open:after{
    width: 100%;
    height: 0;
    content:"";
    position: absolute;
    top: 50%;
    left: 50%;
    background : #FFF;
    opacity: 0;
    transform: translateX(-50%) translateY(-50%) rotate(45deg);
    transition: .2s;
    z-index: -1;
}

.btn-open:hover{
    color: #9ec34b;
}

.btn-open:hover:after{
    height: 240%;
    opacity: 1;
}

.btn-open:active:after{
    height: 340%;
    opacity: 1;
}

機能1の結果

result1.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="result1.css">
  </head>

  <body>

    <table>
        <p id="product-title">製品名</p>
        <p id="product-name">プリンター</p>
    </table>

    <table>
        <p id="spec-title">スペック一覧</p>
        <tr>
            <td class="form-items">電力</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;2.0</td>
        </tr>
        <tr>
            <td class="form-items">最大消費電力</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;2.0</td>
        </tr>
        <tr>
            <td class="form-items">大きさ</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;2.0</td>
        </tr>
    </table>

    <button id="button-back" class="btn-open">
      戻る
    </button> 

  </body>
</html>

result1.css

body {
    font-family: "Avenir Next";
}

p#product-title {
    max-width: 70px;
    font-size: 20px;
    font-weight: bold;
    /*線の種類(点線)2px 線色*/
    border-bottom: dashed 2px #6594e0;
}

p#product-name {
    margin: 100;
    font-size: 20px;
    color: #2b546a;
}

p#spec-title {
    max-width: 140px;
    font-size: 20px;
    font-weight: bold;
    /*線の種類(点線)2px 線色*/
    border-bottom: dashed 2px #6594e0;
}

.form-items {
    color: #2b546a;
    font-weight: bold;
    margin: 0;  
}

.form-items:before {
    content: '●';
    color: #2b546a;
    margin-right: 8px;
}

.btn-open {
    display: inline-block;
    top: 50px;
    left: 0;
    width: 50px;
    height: 35px;
    text-align: center;
    background-color: #9ec34b;
    font-size: 10px;
    border-radius: 10px;
    color: #FFF;
    text-decoration: none;
    font-weight: bold;
    border: 2px solid #9ec34b;
    position: relative;
    overflow: hidden;
    z-index: 1;
}

.btn-open:after{
    width: 100%;
    height: 0;
    content:"";
    position: absolute;
    top: 50%;
    left: 50%;
    background : #FFF;
    opacity: 0;
    transform: translateX(-50%) translateY(-50%) rotate(45deg);
    transition: .2s;
    z-index: -1;
}

.btn-open:hover{
    color: #9ec34b;
}

.btn-open:hover:after{
    height: 240%;
    opacity: 1;
}

.btn-open:active:after{
    height: 340%;
    opacity: 1;
}

準備中ページ

mainte.html

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="mainte.css">
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome-animation/0.0.10/font-awesome-animation.css" type="text/css" media="all" />
  </head>

  <body>
    <h1 class="ready">
        <i class="fas fa-redo-alt fa-spin"></i>
        準備中...
        <i class="fas fa-truck-pickup faa-passing animated"></i>
    </h1>
  </body>
</html>

mainte.css

body {
    font-family: "Avenir Next";
}

.ready {
    text-align:center;
    font-size: 70px;
    color: darkslategray;
}

.fa-redo-alt {
    font-size: 50px;
    font-family: "Font Awesome 5 Free";
    color: #5ab9ff; /*アイコン色*/
    right: 10px;
}

.fa-truck-pickup {
    font-family: "Font Awesome 5 Free";
    color: black;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IFRAMEにコンテンツをフィットさせるには

固定サイズのHTMLを、それよりも小さいサイズのIFRAMEに縮小して表示したかったので、その対処方法です。

課題

たとえば1440px X 1000pxの大きさのHTMLを幅800pxのIFRAMEに表示します。

解決方法

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="default.css">
  </head>
  <body>
    <div id="wrapper">
      <h1>Resize 1440px X 1000px iframe to width 800px</h1>
      <iframe id="iframe" src="iframe-content.html"></iframe>
    </div>
    <a href="iframe-content.html" target="_blank">iframe-content.html</a>
  </body>
  <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
  <script src="default.js"></script>
</html>
default.css
body {
  text-align: center;
}
#wrapper {
  margin: 0 auto 0 auto;
  overflow: hidden;
  width: 800px;
}
#iframe {
  height: 1000px;
  width: 1440px;
}
default.js
(function (window, document, $) {
  let iframe = $('#iframe');
  let wrapper = iframe.parent();
  let width = wrapper.width();
  let ratio = width / iframe.width();
  console.log(`Ratio: ${ratio}`);

  // IFRAME自体は読み込みページの大きさにCSSで適用している。
  // それを#wrapperのサイズにスケールインする。
  // https://stackoverflow.com/questions/166160/how-can-i-scale-the-content-of-an-iframe
  iframe
    .css('-ms-transform',     `scale(${ratio})`)
    .css('-moz-transform',    `scale(${ratio})`)
    .css('-o-transform',      `scale(${ratio})`)
    .css('-webkit-transform', `scale(${ratio})`)
    .css('transform',         `scale(${ratio})`)
    .css('-ms-transform-origin',     '0 0')
    .css('-moz-transform-origin',    '0 0')
    .css('-o-transform-origin',      '0 0')
    .css('-webkit-transform-origin', '0 0')
    .css('transform-origin',         '0 0');

  // #iframeのひとつ上のラッパー#wrapperの高さを同じ倍率で変更する。
  // これをしないとうまくもともとのIFRAMEの高さのままになる。
  wrapper.height(wrapper.height() * ratio);

})(window, window.document, window.jQuery); 

ポイント

  • 同じ倍率で高さも変える必要もあるので、JavaScriptで対応します。
  • 参考サイトにある通り、CSSで縮小します。
  • IFRAMEのサイズは読み込んでいるコンテンツのサイズと同じにしておく。
  • IFRAMEをラッパーで囲みます。CSSで指定したサイズの領域が取られているのでラッパーのdivで高さを調整しています。
  • 面倒だったのでjQueryを使用。

demo

参考サイト

How can I scale the content of an iframe?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google OAuth 2.0 認証を使ったGoogle Sign-Inの実装(サーバー編)

概要

今回はこちらの記事の続きです。
Google OAuth 2.0 認証を使ったGoogle Sign-Inの実装(JS編)
クライアントサイドでログインしてバックエンドサーバーで認証といった感じでやります。

前回の記事でユーザー情報などをレスポンスで取得することができました。
ただこれをこのままサーバーサイドに送ったりするのは危険です。
例えば、ユーザーIDをサーバーに送信する際にユーザーを偽装できちゃったりします。。

なので、その代わりに検証可能なIDトークンを使用して、サーバー側でサインインしているユーザー情報を安全に取得します。

さっそく実装していきましょう。

フロントサイドの実装

まずJSの部分を書きかえます。

JavaScript
function onSignIn(googleUser) {
  var id_token = googleUser.getAuthResponse().id_token; // IDトークンを取得
  // IDトークンをサーバー側に送る処理
}

ここのサーバー側に送る処理はAjax使ったり、hidden属性で送ったりいろいろなやり方があると思いますが、
今回はAjaxのXMLHttpRequestを使用してHTTPリクエストを発行する方法でサーバーとの通信をやって来ます。

先ほどの処理に追加して

javaScript
var req = new XMLHttpRequest();
req.open('POST', '[URL]’);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.onload = function() {
req.send('idtoken=' + id_token);

こんな感じでサーバー側に送信しましょう。
[URL]の部分にはサーバー側のURLを入れましょう。

サーバー側の実装

今回は、JavaのSpring bootを使って実装していきます。

まずは依存関係の追加です。

build.gradle
dependencies {

implementation("com.google.api-client:google-api-client:1.30.5")

}

Googleクライアントライブラリを使えば簡単にIDトークンの検証ができます。

Java
 GoogleIdTokenVerifier verifier =
        new GoogleIdTokenVerifier.Builder(
                new NetHttpTransport(), JacksonFactory.getDefaultInstance())
            .setAudience(Collections.singletonList("YOUR_CLIENT_ID.apps.googleusercontent.com"))
            .build();

 var idtokenStriing = getIdToken(); // 取得したIDトークン

 GoogleIdToken idToken = verifier.verify(idTokenString); // IDトークン検証


YOUR_CLIENT_IDには自分のクライアントIDを入れてください。

もしGoogleクライアントライブラリを使わない場合はGoogleの公開鍵(PEM形式)を使用して、トークンの署名を検証する方法もありますが、GoogleでもGoogleクライアントライブラリを使って検証することを推奨しているので使いましょう。

あとはユーザー情報を取得するだけです。

Java
  Payload payload = idToken.getPayload();

  String userId = payload.getSubject(); // ユーザーID
  String email = payload.getEmail(); // ユーザーメールアドレス
  String name = (String) payload.get("name"); // ユーザー名
  String pictureUrl = (String) payload.get("picture"); // ユーザープロフィール画像

こんな感じで取得できちゃいます。

まとめ

今はいろんなサイトでOAuth認証使ってるところが増えてますね。
今回はGoogleですがFacebookやAppleなどのOAuth認証もまたあげていこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者によるプログラミング学習ログ 230日目

100日チャレンジの230日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

230日目は

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[React]テーブルのセルを結合する

概要

  • Reactで配列をループさせてテーブルを描画する
  • 特定の項目についてセルを結合させたい

作成イメージ

スクリーンショット 2020-02-05 15.01.31.png

  • 共通する項目についてセルを結合する

調べたこと

<table border="3">
  <tr>
    <td rowspan="3">垂直方向の結合</td>
    <td>データ1</td>
  </tr>
  <tr>
    <td>データ2</td>
  </tr>
  <tr>
    <td>データ3</td>
  </tr>
</table>

実装

  • 表示する配列
src/constants/GroupList.js
import { nogizaka, keyakizaka, hinatazaka } from "./Color";

const groupList = [
  {
    id: 1,
    name: "乃木坂46",
    color: nogizaka.color,
    memberList: [
      {
        id: 1,
        name: "齋藤飛鳥",
        age: 21
      }
    ]
  },
  {
    id: 2,
    name: "欅坂46",
    color: keyakizaka.color,
    memberList: [
      {
        id: 1,
        name: "渡邉理佐",
        age: 21
      },
      {
        id: 2,
        name: "小林由依",
        age: 20
      }
    ]
  },
  {
    id: 3,
    name: "日向坂46",
    color: hinatazaka.color,
    memberList: [
      {
        id: 1,
        name: "齊藤京子",
        age: 22
      },
      {
        id: 2,
        name: "小坂菜緒",
        age: 17
      },
      {
        id: 3,
        name: "上村ひなの",
        age: 15
      }
    ]
  }
];

export default groupList;

  • 表示するコンポーネント
src/App.js
import React from "react";
import { Table } from "react-bootstrap";
import styled from "styled-components";
import groupList from "./constants/GroupList";

const ColorTr = styled.tr`
  color: ${({ color }) => color};
`;

function App() {
  return (
    <Table bordered>
      <thead>
        <tr>
          <th>グループ</th>
          <th>名前</th>
          <th>年齢</th>
        </tr>
      </thead>
      <tbody>
        {groupList.map(group =>
          group.memberList.map((member, i) =>
            i === 0 ? (
              <ColorTr key={member.id} color={group.color}>
                <td rowSpan={group.memberList.length}>{group.name}</td>
                <td>{member.name}</td>
                <td>{member.age}</td>
              </ColorTr>
            ) : (
              <ColorTr key={member.id} color={group.color}>
                <td>{member.name}</td>
                <td>{member.age}</td>
              </ColorTr>
            )
          )
        )}
      </tbody>
    </Table>
  );
}

export default App;

行ったこと

  • 配列の個数を結合させる行数としてrowspanの値に設定
src/App.js
<td rowSpan={group.memberList.length}>{group.name}</td>
  • ループさせる配列のインデックスをとり、先頭行の場合(インデックスが0の場合)とそうでない場合を分岐
src/App.js
{groupList.map(group =>
  group.memberList.map((member, i) =>
    i === 0 ? (
      <ColorTr key={member.id} color={group.color}>
        <td rowSpan={group.memberList.length}>{group.name}</td>
      // 省略
      </ColorTr>
    ) : (
      // 省略
    )
  )
)}

終わりに

  • とりあえず実現してみたけど何だか冗長・・・
  • もっと良い方法をご存知の方いましたらコメントください

余談

本題とは全く関係ありませんが、今回使用したカラーコードはそれぞれ以下を参考にしています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS LightsailのLAMP環境でSSIインクルード

あるとおもうんです。
受託の制作をしててステージング環境とかない場合とか。

あるとおもうんです。
先方のサーバーがレンタルサーバーでApacheなことが。

あると思うんです。
自社の環境がAWSでLightsailって1ヶ月無料だしここでプレビューしちゃえばよくね?ってことが。

普通にやってたら特に何にも気にすることなく進行できると思うんですけど、
あるとおもうんです。
SSIインクルードしてるHTMLがあることが!!

同じ境遇の方の一助になればという思いで残しておきます。

まず調べたこと

SSIがhtmlで動くようにするっていうのをググると大抵.htaccessに書く〜とかhttpd.confに書く〜というのがヒットするかと思います。
しかしLightsailなどのキーワードを入れると全くと言っていいほどヒットしない。
(キーワード選定がおかしいのかもしれない)

.htaccessに書いてもうんともすんともしない。
これはhttpd.confで設定しないと動かなそうだな〜とあたりをつけて設定を書いては再起動を繰り返しました。

持つべきものは同僚だな!

しかしなかなか動かないのでslackで「LightsailでSSIが動かない・・・。」とチャットしたら
「SSIは脆弱性になりうるんで、デフォルトで使えないようになってたりしそうっすね。そもそもモジュールが入ってなかったりして。」と返信がきた。

ん?神か?

httpd.confの設定と.htaccessの記述

httpd.confを覗いてみたらモジュールがコメントアウトされていたので
105行目あたりのコメントを外して再起動!

- #LoadModule include_module modules/mod_include.so
+ LoadModule include_module modules/mod_include.so

あとは.htaccessにこんな感じで書いたらインクルードできると思います。

Options +Includes
AddHandler server-parsed .html

おまけ

LightsailはBitnamiなので、httpd.confの他にも

/opt/bitnami/apache2/conf/ssi.conf
/opt/bitnami/apache2/conf/bitnami/bitnami.conf

と設定ファイルがあります。
SSIインクルード以外の機能は試してないですが、これらのファイルで設定すれば動くようになるかもしれません。

さいごに

SSIのセキュリティに関しては詳しくはないですがあまりよろしくないと思うので、
タスクランナーなどで静的にHTMLに書き出しできないかなど検討をしてみてください。

それと持つべきものは同僚だな!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jenkinsの成果物HTMLにCSSを適用する

はじめに

Jenkinsのビルド結果を確認するためにHTMLを成果物として登録したはいいものの、インラインで定義したCSSが適用されない…
という状況に遭遇したのでメモ

原因

JenkinsはContent Security Policy(CSP)のデフォルト設定をキツめにしているようです。以下がデフォルト設定です。

sandbox; default-src 'none'; img-src 'self'; style-src 'self';

CSSは自ドメインのファイルのみ許可されていて、インラインでの実行は許可されていません。

解決方法

解決方法としては以下の2つが考えられますが、今回は後者を選択しました。

  • デフォルト設定を変更し、インラインで実行できるようにする
  • デフォルト設定に従う(CSSを表示できる状態に変更する)
    • CSSをファイル化して、Jenkinsと同ドメイン配下に配置
    • HTMLは上記CSSファイルを読み込む

Jenkinsはユーザが静的コンテンツを配置するための仕組みを用意していますので、そこにCSSファイルを配置します。

例として、$JENKINS_HOME/userContent/assets/css/test.cssに配置した場合、https://[任意のドメイン]/jenkins/userContent/assets/css/test.cssでアクセス可能となります。

あとはHTMLでCSSファイルを読み込むようにすれば完了です。

...
<link rel="stylesheet" href="/jenkins/userContent/assets/css/test.css">
...

終わりに

今回は、

  • 成果物のHTMLはJenkins上でのみ閲覧
  • 自作のHTML

という前提条件だったのでCSPを変更せずに解決できましたが、大体の場合はCSPを変更する必要があると思います。その場合は、以下のように設定を変更して対応できるかと思います。
JenkinsのClover pluginを利用したカバレッジレポートページにCSSが適用されない

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoogleTagManagerを使ってHTML要素の追加や削除を行う

まえがき

webアプリケーションで特定条件時のみ画面のカスタマイズを行いたい場合に、あんまりソースコードにif文いっぱい書きたくないな……と思ったのでGoogleTagManager(以下GTM)を使用することにしました。
Analyticsと組み合わせて使われることが多い(と思われる)GTMですが、Javascriptを使用してソースコード本体に手を加えずにHTML要素のカスタマイズを行うこともできます。

タグ作成

GTMから「新しいタグを作成」を押下し、「タグの設定」を選択します。
スクリーンショット 2020-02-05 10.50.19.png

タグタイプで「カスタムHTML」を選択します。
スクリーンショット 2020-02-05 11.16.25.png

タグの設定を行う
スクリーンショット 2020-02-05 11.17.20.png
「HTML」の箇所にJavascriptを記載します。
今回はシンプルにdiv要素の追加を行うことにします。要素の削除や、CSSスタイルの変更も可能です。
Javascriptは「ライブラリを使わない素のJavaScriptでDOM操作」を参考にさせていただきました。

<script>
  var container = document.querySelector('.test-tag');
  container.innerHTML = '<div>グーグルタグマネージャテスト挿入</div>';
</script>

詳細設定から、タグ配信の優先度を100に設定しておきました。
タグを複数設定した場合、詳細設定でそれぞれのタグの優先順位や順序付けが可能なので色々調整が効きます。

トリガー作成

タグの作成が完了したら「トリガーの選択」右上にある「+」マークからトリガーを新規追加します。

今回トリガーは「ページビュー > ページビュー」にしました。
スクリーンショット 2020-02-05 11.32.55.png

サンプルでは特定IDのページだけカスタム画面を見せたいという設定なので、「一部のページビュー」を選択して条件を記載します。
スクリーンショット 2020-02-05 11.33.20.png

サイトに差し込み用の要素を仕込む

<div class="test-tag"></div>

メッセージを差し込みたい位置に、GTMで指定したクラスを入れておきます。
これだけ。

プレビューで確認し、問題なければ公開します。
GTMのプレビューと公開を正しく行おう

メリット

  • if文でソースコードを汚さずに済む。
  • デプロイ不要。画像やリンクの追加も楽。
  • かなり柔軟に設定できるので、慣れるとソースがりがり書くよりスムーズ。
  • GTMのバージョン管理も便利。
  • 運用者と開発者が異なっており、細かい変更が定期的に入る箇所の修正を運用者が行える(ニュースとか?)。

デメリット

  • うっかり不具合があった場合に、原因がGTMに記述したscriptなのかソースコード本体側にあるのかの検証がややめんどうくさい。
  • 使用しているクラスやIDの管理をきちんと行わないと、後日混乱しやすい。(「あれ、このクラス使ってない?いらないなら消していい?」「あーそれGTMで使ってます」)
  • Git上でソースコードと合わせて一括でバージョン管理できない。

まとめ

トリガーにCookieを使用することで、LPページ踏んだお客さんにはフォームにキャンペーンコード入力欄を表示するけど、LPページ見てないお客さんにはキャンペーンコード入力欄は非表示にするよ!
Javascriptにエラーがあったときにブラウザでアラート出すよ!
QAページのスクロール距離が長い場合に、ヘルプチャットへの誘導を行うよ!
などなど、いろんなことがGTMでできました。
便利ですが、チーム開発では管理がやや煩雑になるなあという印象はあるため、うまく使っていきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

レスポンシブ設計 キホンの基本 part2~flex-wrap: wrap;

前回はレスポンシブのための一歩目をやりました⤵︎
https://qiita.com/zakaryo/items/ee0a799f4d1bb61f2517

今回は折り返しについてやっていきます。

いざdisplayをflexにし横並びにすることができたとしても、

そのままだと子要素のコンテンツが増えたときに、延々と詰め込まれてしまいうことになります。

こんな感じに。

style.css
 .container {
display: flex;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}

スクリーンショット 2020-02-05 3.06.46.png

本来300x300の正方形を並べたいのに、画面いっぱいに詰め込まれ縮んでしまいます。

そこで親要素にflex-wrap:wrap;を指定してみましょう。

style.css
 .container {
display: flex;
flex-wrap: wrap;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}

そうするとこうなります。
スクリーンショット 2020-02-05 3.19.45.png

このように無理につめこまれるのではなくて、width:300px;が適用され

はみ出る分は一段下に落とされます。

さらに親要素にmax-widthを指定してあげれば1段に何個の子要素を入れるかを決めることができます。

style.css
 .container {
display: flex;
flex-wrap: wrap;
max-width:700px;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}

スクリーンショット 2020-02-05 3.30.44.png

実際は下に子要素の数分続いています。

以上のようにするとflexboxにおいて折り返しができるのではないでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTML <%○○>タグリファレンスの種類と書き方

タグリファレンスとは

<%button>ボタンの作成
<%input>入力ホーム
<%body>文書情報・構造
<%!DOCTYPE>文書情報・構造

があったりします。

書き方としては

HTML

<button type="submit" class="button1">
  <i class="fas fa-search"></i> 検索
</button>

HAML

%button{type: "submit", class: "button1"}
  %i.fas.fa-search>
  検索

または

%button.button1{type: "submit"}
  %i.fas.fa-search>
  検索

"type"で属性を持たせたり
"value"で値を指定したり
"class"でクラスを持たせて色の指定や、大きさを変更できるようになります。

↓<%input>の例↓

HTML

<label>
  <input type="submit" value="送信する">
</label>

HAML

%label
  %input{:type => "submit", :value => "送信する"}/

参考文献
★HTMLタグリファレンス(ABC順)
★HTMLタグリファレンス(目的別)
inputの使い方とtype属性の一覧をサンプル付きで紹介
submitボタンのアイコンにアイコンフォント(Font Awesome)を使う

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HAML %buttonをつけてsubmitボタンにフォントオーサムのアイコンをつける

submitボタン(送信用ボタン)にフォントオーサムのアイコンをつけたい。
しかし以下のようにやってしまうと、うまく行きません。

_main_bar.html.haml
.form
    = form_for [@group, @message] do |f|
      .form__new-message
        .form__new-message__input-box
          = f.text_field :content, class: 'text', placeholder: 'メッセージを入力'
          = f.label :image, class: 'image' do
            = icon('fas', 'image', class: 'icon')
            = f.file_field :image, class: 'hidden'
        = f.submit '送信', class: 'submit-btn'         #今回見るのはここの行
        = icon('fas', 'paper-plane', class: 'plane')   #今回見るのはここの行

main_bar.scss
      .submit-btn {
        align-items: center;
        height: 50px;
        width: 100px;
        margin-left: 15px;
        padding: 0 20px 0;
        background-color: #38aef0;
        color: white;
        box-shadow: 1px 1px 2px #999999;
        border-style: none;
      }
      .fas.fa-paper-plane {
        color: white;
        font-size: 25px;
      }

このようになります。↓
紙飛行機が送信ボタンからはみ出てしまいました。

スクリーンショット 2020-02-05 1.47.45.png

なので、このように変更して紙飛行機を送信ボタンの中に入れます。

_main_bar.html.haml
  .form
    = form_for [@group, @message] do |f|
      .form__new-message
        .form__new-message__input-box
          = f.text_field :content, class: 'text', placeholder: 'メッセージを入力'
          = f.label :image, class: 'image' do
            = icon('fas', 'image', class: 'icon')
            = f.file_field :image, class: 'hidden'
        %button{type: "submit", class:'btn'}   #今回見るのはここの行
          %i.fas.fa-paper-plane          #今回見るのはここの行
          .letter                  #今回見るのはここの行
            送信                   #今回見るのはここの行

main_bar.scss
      .btn {
        align-items: center;
        height: 50px;
        width: 100px;
        margin-left: 15px;
        padding: 0 20px 0;
        background-color: #38aef0;
        color: white;
        box-shadow: 1px 1px 2px #999999;
        border-style: none;
        display: flex;
      }
      .fas.fa-paper-plane {
        color: white;
        font-size: 17px;
      }
      .letter {
        font-size: 16px;
        margin-left: 5px;
      }

無事成功( ^∀^)

スクリーンショット 2020-02-05 2.07.07.png

できましたね!!

↓↓変更した部分↓↓

_main.html.haml
= f.submit '送信', class: 'submit-btn'
= icon('fas', 'paper-plane', class: 'plane')

の部分を

_main.html.haml
%button{type: "submit", class:'btn'} 
  %i.fas.fa-paper-plane          
  .letter                  
    送信                   

↑↑変更した部分↑↑

のように書き方を変えました!!

type属性では
submit(送信ボタン)
reset(リセットボタン)
button(汎用的に使える押しボタン)
が使用可能です!!

%button{type: "submit", class:'btn'} ここのtype: ""の中身の部分の事です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【未経験】ポートフォリオサイトを作成してみた。

自己紹介

現職は不動産管理会社のフロントマンをしています。
WEBデザイナーへの転職を考えてHTMLとCSSを勉強中です。
主にProgateを利用して勉強を進めております。

ポートフォリオサイト

Photoshopで作成したデザインを元にコーディングしてみました。
デザインする際には「どのようにしたらコーディングできるか」を意識しました。
デザイン~コーディングまで1週間と少しくらいかかりました。
偶然に3連休が入らなければ確実に終わらなかったと思います(笑)。

1.ポートフォリオサイト

プロフィール・スキル・作品・連絡先をシンプルにまとめました。
Progateのレッスンでは与えられていた画像のサイズなど、
基本情報から自分で考えなければならなかったのが大変でした。

https://tomohiro34685.github.io/portfolio-site/

2.架空のサイト

ポートフォリオサイトに載せる作品として作成しました。
デザインはファッションブランドのサイトを参考に作成しました。
まだ掲示できる作品としてのサイトが殆どないので、
勉強のためにも少しずつ増やしていきたいと思っています。

https://tomohiro34685.github.io/portofolio/

使用ソフト・参考サイト

1.使用ソフト
- Photoshop
- Atom

2.参考サイト
- Progate
- Unsplash

作ってみての感想

直すべき箇所は枚挙に暇がありませんが、サイトを作り上げた達成感があって嬉しいです。
サイトのデザインからコーディングまで、すべてを自分一人でやるのはとても苦労しましたし、途中で投げ出したくなる瞬間もありましたが、1つ自身に繋げられたと思います。
今はまだ知識もないので、その場しのぎの対応を調べて試すという繰り返しのサイトなので、とても不格好なものになっていると思います。
これからも自己研鑽を続けていくので、少しずつでもサイトを更新していけたらと思っております。
最後までご覧になっていただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む