20191209のCSSに関する記事は14件です。

年末まで毎日webサイトを作り続ける大学生 〜52日目 JavaScriptで神経衰弱ゲームを作る〜

はじめに

こんにちは!@70days_jsです。

今日は神経衰弱を作りました。

全部クリアすると、なんと!

最後にとっておきの画像を見ることができます!
(大声では言えないですが、思わず興奮してしまう画像です...)

ぜひやってみてください。

ちなみにバグもありまして、素早く連続でクリックすると何枚もカードが開けてしまうのでご了承ください。直す時間がありませんでした。

今日は52日目。(2019/12/9)
よろしくお願いします。

サイトURL

https://sin2cos21.github.io/day52.html

やったこと

外観と動作はこんな感じです。↓
test3.gif

ほぼ全てJavaScriptで作りました。一部cssのアニメーションも使っています。
のでhtmlは何もなし↓

<body></body>

JavaScript長いですが一応全て載せます↓

window.onload = function() {
  createCardWrapper(); //wrapperを作る
  createCard(); //cardを作る
};

let divWrapper; //一番大枠のdiv
let countDisplay;
let countDisplaySpan = document.getElementById("countDisplaySpan");
let card = [
  { 0: "" },
  { 1: "" },
  { 2: "" },
  { 3: "" },
  { 4: "" },
  { 5: "" },
  { 6: "" },
  { 7: "" },
  { 8: "" },
  { 9: "" },
  { 10: "" },
  { 11: "" },
  { 12: "" },
  { 13: "" },
  { 14: "" },
  { 15: "" }
]; //それぞれのcardにつけるid
let image = ["1", "2", "3", "4", "5", "6", "7", "8"]; //cardの画像名
let imageNumber = 0;
let beforeCard = ""; //前にクリックしたcard
let id; //クリックしたcardのid(=key)
let countClick = 2; //1回目か2回目かの判断
let goal = 0; //全て当てたかどうかの判断

function clicked(e) {
  open(e); //cardクリック時のモーション
  successOrFailure(e);
}

//cardクリック時のモーション
function open(e) {
  id = e.target.id;
  e.target.classList.add("click-none");
  e.target.classList.add("card-rotate");
  delayImageDisplay(1000).then(function() {
    e.target.style.backgroundImage = "url(day52/" + card[id][id] + ".png)";
    e.target.classList.remove("card-rotate");
  });
}
function successOrFailure(e) {
  if (countClick % 2 == 0) {
    //1回目

    countClick++;
    countDisplaySpan.innerHTML =
      countClick -
      2 +
      ", 奇数, 前回のカード" +
      beforeCard +
      ",ポイント: " +
      goal;
    beforeCard = id;
  } else {
    //2回目、かつ成功
    if (card[beforeCard][beforeCard] === card[id][id]) {
      console.log("success");
      countDisplaySpan.innerHTML =
        countClick -
        2 +
        ", 偶数, 前回のカード" +
        beforeCard +
        ",ポイント: " +
        goal;
      beforeCard = id;
      countClick++;
      goal += Number(card[id][id]);
      if (goal === 36) {
        setTimeout(goaal, 2000);
      }
    } else {
      //2回目、かつ失敗
      e.target.classList.add("card-rotate");
      countClick++;
      countDisplaySpan.innerHTML =
        countClick -
        2 +
        ", 偶数, 前回のカード" +
        beforeCard +
        ",ポイント: " +
        goal;
      delayImageDisplay(1000)
        .then(function() {
          e.target.classList.remove("card-rotate");
        })
        .then(function() {
          let before = document.getElementById(beforeCard);
          beforeCard = id;

          setTimeout(function() {
            before.style.backgroundImage = "url(day52/day52_card.png)";
            e.target.style.backgroundImage = "url(day52/day52_card.png)";
            console.log(before);
            console.log(e.target);
            e.target.classList.remove("card-rotate");
            e.target.classList.remove("click-none");
            before.classList.remove("click-none");
          }, 1000);
        });
    }
  }
}

//image配列の順番をシャッフルする
function shuffle() {
  for (var i = image.length - 1; i > 0; i--) {
    let random = Math.floor(Math.random() * (i + 1));
    let tmp = image[i];
    image[i] = image[random];
    image[random] = tmp;
  }
}

//一番大枠のwrapperを作成する関数
function createCardWrapper() {
  countDisplay = document.createElement("div");
  countDisplaySpan = document.createElement("span");
  countDisplaySpan.setAttribute("id", "countDisplaySpan");
  countDisplay.innerHTML = "クリック回数: ";
  countDisplay.appendChild(countDisplaySpan);
  document.body.appendChild(countDisplay);

  divWrapper = document.createElement("div");
  divWrapper.setAttribute("id", "divWrapper");
  document.body.appendChild(divWrapper);
}
//cardを16枚作る関数
function createCard() {
  shuffle(); //画像をシャッフルする
  for (var i = 0; i < card.length; i++) {
    let div = document.createElement("div");
    let key = Object.keys(card[i]); //a,b..pと順番に入る
    div.setAttribute("id", key);
    card[i][key] = image[imageNumber]; //cardと画像が結びついた(画像は2枚ずつ)
    div.setAttribute("class", "card");
    // div.style.backgroundImage = "url(day52/" + image[imageNumber] + ".png)";
    if (imageNumber >= 7) {
      imageNumber = 0;
      shuffle(); //画像をシャッフルする
    } else {
      imageNumber++;
    }
    divWrapper.appendChild(div);
    div.addEventListener("click", clicked);
  }
  console.log(card);
}

//画像の表示を遅らせるための関数
function delayImageDisplay(delay) {
  return new Promise(function(resolve) {
    setTimeout(resolve, delay);
  });
}
function goaal() {
  goalDiv = document.createElement("div");
  goalImg = document.createElement("img");
  goalDiv.innerHTML = "おめでとうございます!";
  goalImg.setAttribute("class", "goalImg");
  goalDiv.setAttribute("class", "goalDiv");
  goalImg.setAttribute("src", "day52/secret.jpg");
  goalDiv.appendChild(goalImg);
  document.body.appendChild(goalDiv);
}

cssも一応全て載せておきます。↓

body {
  margin: 0;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

img {
  max-width: 100%;
  max-height: 100%;
}

#divWrapper {
  width: 600px;
  height: auto;
  background-color: rgba(80, 80, 200, 0.3);
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}

.card {
  display: inline-block;
  width: 130px;
  height: 130px;
  background-color: rgba(50, 50, 50, 0);
  /* border: solid 1px black; */
  margin: 1%;
  background-image: url("day52/day52_card.png");
  background-size: cover;
}

.card:hover {
  opacity: 0.2;
}

.card-rotate {
  animation: rotate;
  animation-duration: 1s;
}

@keyframes rotate {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(92deg);
  }
}

.click-none {
  pointer-events: none;
}

.goalDiv {
  position: absolute;
  background-color: black;
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  flex-direction: column;
  font-size: 3em;
}

.goalImg {
  display: inline-block;
}

肝になる部分

ちょっと今回は長いので大事なところだけ説明していきます。

let card = [
...

この変数↑は配列ですが、その中身はhash形式で情報を保存しています。↓

{ 0: "" },
{ 1: "" },
{ 2: "" },
...

神経衰弱のカードにはそれぞれidが割り振られており、このhashのキー(0~15)はそのidと全て対応しています。
このhashはのちにvalueに1~8の値を持ちます。
この数字は画像の名前と一致しており、それぞれ2回ずつhashに割り当てることで対になる2枚のカードを実現しています。
これがhashのvalueに入る数字です。↓

let image = ["1", "2", "3", "4", "5", "6", "7", "8"]; //cardの画像名

このままでは順番通りに画像が入ってしまうので、image配列の中身をシャッフルします。↓

function shuffle() {
for (var i = image.length - 1; i > 0; i--) {
let random = Math.floor(Math.random() * (i + 1));
let tmp = image[i];
image[i] = image[random];
image[random] = tmp;
}
}

promiseを使う

ちなみに、今回promiseも少し使ってみました。
やっぱりまだ理解しきれていないですが。↓

function delayImageDisplay(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}

function open(e) {
id = e.target.id;
e.target.classList.add("click-none");
e.target.classList.add("card-rotate");
delayImageDisplay(1000).then(function() {
e.target.style.backgroundImage = "url(day52/" + card[id][id] + ".png)";
e.target.classList.remove("card-rotate");
});

ただ、しっかり順番通りに動いてくれているので、なんとなく便利だということは分かりました。
いずれちゃんと理解しようと思います。

ゴールページについて

神経衰弱を全てやり終えたら思わず興奮してしまう画像を用意しています。

変数を用意します。↓

let goal = 0;

カードが当てることができたら、goal変数に画像の値分(0~8)数値を足します。↓

goal += Number(card[id][id]);

画像はは0~8なので、全て足し合わせると36になります。36になると関数を実行するようにしています。↓

if (goal === 36) {
setTimeout(goaal, 2000);
}
} else {...

関数の中身です。secret.jpgが例の画像です。↓

function goaal() {
goalDiv = document.createElement("div");
goalImg = document.createElement("img");
goalDiv.innerHTML = "おめでとうございます!";
goalImg.setAttribute("class", "goalImg");
goalDiv.setAttribute("class", "goalDiv");
goalImg.setAttribute("src", "day52/secret.jpg");
goalDiv.appendChild(goalImg);
document.body.appendChild(goalDiv);
}

secret画像は国宝級の画像を用意しました。
皆さんもぜひ試してみてください!(アプリでは全て見れます)↓
スクリーンショット 2019-12-09 21.54.06.png

感想

ちょっと今日は説明が意味不明すぎることになっていると思います。
申し訳ありません。

というのも、手当たり次第に作っていたら色々と複雑になってしまい、全てを言語化していたら膨大な量になってしまうと判断したからです。
今後は最初にきちんと設計して、なるべくシンプルなコードを書けるように尽力します

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。

参考

  1. アイコン素材ダウンロードサイト「icooon-mono」 | 商用利用可能なアイコン素材が無料(フリー)ダウンロードできるサイト | 6000個以上のアイコン素材を無料でダウンロードできるサイト ICOOON MONO
  2. パブリックドメインQ:著作権フリー画像素材集

画像を使用させていただきました。

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

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

100日チャレンジの179日目

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

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

179日目は

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

技術ポートフォリオを作った話

つい先月,自分のgithubアカウントで技術ポートフォリオを作成した.→ tackkyのポートフォリオ
どうしてgitもhtmlも慣れていないのに作ろうと思ったのか,その辺の話も含めて記事にする.

技術ポートフォリオは何に役立つ?

1. 就活で使える

1. 逆求人

これが一番大きい. 特に最近IT系の就活では逆求人(企業様の方から連絡が来る就活)で,まず自分の情報を見ていただく.

例えば,

  • 研究室での研究内容
  • 資格,その他技術的にやってきたこと

など.この場合,研究内容だけ突き詰めて研究している方ならそこを詳しく書けばいいけれど,私などのようにいろんな技術をつまみ食いしているような人には不利になる.githubで公開リポジトリーとしてアップするという手もあるけれど,やはり就活では技術に詳しくない人事の方も見ているので,見た目にも綺麗なwebページが一番企業様へのインパクトは大きい.

2. エントリーシート

このような目的で作成されたポートフォリオは,エントリーシートの作成にも役立つ.
研究内容にも言及していれば,そのポートフォリオ記事を参考に書くことができるし,アピールポイントにこのページのURLを貼ることができる.(後たまに,技術ポートフォリオがあれば教えてくださいみたいな欄があることがある)

2. 勉強になる

最後に,HTMLとCSSを使うので何より勉強になる.私は研究室や講義でHTMLは兎も角CSSは使用したことはないけれど,技術ポートフォリオを作ることはHTMLとCSSの使用経験につながる.

技術的観点から

GitHub

技術者になる者,Github含め,Gitは使えるようになった方がいい.私は研究を他の人と共同でやっていないので研究室としてgitを使用することはないけれど,バージョン管理システムとして少し前から使い始めた.特に共有する相手がいなくてもgitはおすすめ.よく考えなくてもgitは バージョン管理システムである.私が最近使用しているgitの使い道が参考になるかもしれない.

  • 理由1 論文を書くときにも使える.

    参考URL:ライトに知りたい人はこちらしっかり読みたい人はこちら

    ナウいヤングは論文執筆にGitHubを使う
    まず、学会や学校などのテンプレートを導入して正しくコンパイルされる状態にしたものをfirst commitとしてmasterブランチにコミットします。
    次にmasterから1stブランチを切って、GitHub上でmasterブランチにPull Requestを送ります。
    PRを送ったら、1stブランチでガリガリ初稿を書いていきます。コミットの粒度は小節毎だったり段落ごとだったりしますが、これは執筆が進んでいくと変わっていくと思います。後半になると修正箇所も少なくなるので「○○先生添削分修正」などとふわっとしてきます。
    添削の依頼をして返ってきたら、1stブランチをmasterにマージします。そして2ndブランチを切ってPRを送って……の繰り返しです。

  • 理由2 スライド管理にも使える.
    様々な版(学会用,卒業発表用等)とわけることができる.次のページがわかりやすすぎるので説明は割愛.

    参考URL:ここのページからスライド管理するようになった

HTMLとCSS

…ざっくり仕組み使えるようになりたいなって思ってた,それだけです.講義で扱うのはHTMLだけなのでやっぱり心寂しい.

技術ポートフォリオの作り方

作ってみた流れ.

1.githubでページを作る

GitHub Pagesというサービスがある.これは,Githubに登録したリポジトリーをwebページとして公開することができるGitHubのサービスである.settinggithub pagesの項目があるのでそこでソースをマスターブランチに登録するだけである.とりあえずhello worldとでも書いたindex.htmlを用意して公開すればいい.

一応:github pagesによる静的サービス公開方法

2.サンプルページを探してくる

結構フリーでHTMLとCSSのソースは落ちている.特にtemplate free engineer portfolioとでも検索すれば,ごまんとフリーテンプレートが見つかる.私は以下のサイトから見つけてきた.(確か.)
50 free portfolio website templates 2019

3.自分仕様に変更する

後はダウンロードしたデータを自分仕様にカスタマイズするだけだ.先のテンプレートサイト等には結構な量のデータがあるので,私のような初心者エンジニアにはいらない部分が多すぎる.なので「いらない部分を削る」作業が必要になる.これには,どこからどこまで削っても問題なく動作するのか判断するために,HTMLの構造を理解している必要がある.CSSは色のテイストや配置などを変えたくなってから触る方が楽なのでとりあえず置いておいて,HTMLCSSの順でカスタマイズするのがおすすめ.

おめでとう!

ここまでのプロセスでやっと技術ポートフォリオをつくることができる.新しいことに取り組むことがあれば,どんどん追加して素晴らしいポートフォリオにしよう.

参考サイト

エンジニア向けのポートフォリオサイトまとめ
ポートフォリオをGitHub で公開する

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

jQueryプラグインの実践

jQueryプラグインの実践をしてみた

こんにちは。ちょっとずつ学習したことを実践して投稿します。

やったこと

jQueryとjavaScriptを使って、
1. 画像をクリックしたら、そのフォントサイズを表示する。
2. ボタンをクリックしたらテキストを取得し表示する

コード

部分的にコードを抜粋します。
index.htmlに画像などいろいろと要素を埋め込んでいきます。
jquery.showsize.jsの方へ画像をクリックした際の動作を埋め込んでいき、外部ファイルとして取得します。

index.html
          <button type="button" name="button">
            <p><img src="img/hoge.jpg"></p>
            <div id="cat1-button"><p id="text-a">click</p></div>
          </button>
          <button type="button" name="button">
            <p><img src="img/hogehoge.jpg"></p>
            <div id="cat2-button"><p id="text-b">click</p></div>
          </button>
          <button type="button" name="button">
            <p><img src="img/hogehogehoge.jpg"></p>
            <div id="cat3-button"><p id="text-c">click</p></div>
          </button>
          <button type="button" name="button">
            <p><img src="img/hogehogehogehoge.jpg" data-size="30"></p>
            <div id="cat4-button"><p id="text-d">click</p></div>
          </button>
        </div>

        </ul>

          <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
          <script src="jquery.showsize.js"></script>


    <script>
      $(function(){
        $('img').showsize({
        });
      });

{
document.getElementById("cat1-button").onclick = function() {
  document.getElementById("text-a").innerHTML = "hoge";
};
}
{
      document.getElementById("cat2-button").onclick = function() {
        document.getElementById("text-b").innerHTML = "hogehoge";
      };
}
{
      document.getElementById("cat3-button").onclick = function() {
        document.getElementById("text-c").innerHTML = "hogehogehoge";
      };
}
{
      document.getElementById("cat4-button").onclick = function() {
        document.getElementById("text-d").innerHTML = "hogehogehogehoge";
      };
}
    </script>
  </div>
jquery.showsize.js
;(function($) {

    $.fn.showsize = function(options) {

        var elements = this;

        elements.each(function() {

            var opts = $.extend({}, $.fn.showsize.defaults, options, $(this).data());
            $(this).click(function() {
                var msg = $(this).width() + ' x ' + $(this).height();
                $(this).wrap('<div style="position:relative;"></div>');
                var div = $('<div>')
                            .text(msg)
                            .css('position', 'absolute')
                            .css('top', '0')
                            .css('background', 'black')
                            .css('color', getRandomColor())
                            .css('font-size', opts.size + 'px')
                            .css('opacity', opts.opacity)
                            .css('padding', '2px');
                $(this).after(div);
            });
        });

        return this;

    };

    function getRandomColor() {
        var colors = ['white', 'skyblue', 'orange', 'green'];
        return colors[Math.floor(Math.random() * colors.length)];
    }

    $.fn.showsize.defaults = {
        size: 10,
        opacity: 0.9
    };

})(jQuery);

後記

複数のscriptが続く際には、{}で括るという初歩的なことが大事だと痛感しました。
このコードをサンプルとしてご自由にご利用ください。

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

はじめてぶらうざののべるげーむをつくってみたの!

はじめてぶらうざののべるげーむをつくってみたの!

自分でノベルゲーを作りたくなったので、モチベ維持のためにもQiita記事にしました。
ゆくゆくは簡単にブラウザノベルゲームを作れるソフトでも作りたいなと思ってるので、その下調べ的ななにがしですね。

Qiita記事は初心者なので、なんか書いた方がいいこととかあれば教えてくだせぇ。
それではさっそく行きましょう。

Chapter 0.使用言語

  • HTML
  • CSS
  • JavaScript(JQuery)

Chapter 1.とりあえずタイトル画面つくるかのぅ…。

タイトル画面がないと始まりません。

1.仮でとりあえず作っていきます。

StartMenu.jpg

html
<body>
    <h1>ノベルゲーム!</h1>

    <a href="">続きから</a>
    <a href="">最初から</a>
    <a href="">環境設定</a>
</body>
css
*{
    text-decoration:none;
    color:black;
}
h1{
    background-color:rgba(255,0,0,.3);
}
a{
    display:block;
    background-color:rgba(0,255,0,.3);
}

必要なものはこれくらいでしょうか。
これをもとにCSSでデザインを作っていきますが、上の通りbackground-color:rgba(??,??,??,.3);などと背景色をつけるとどの要素がどこにいるかわかりやすいですね。

2.タイトルとメニューは中央寄せにしたいですね。

そこで、text-align:center;をh1とaに対して指定します。
また、それぞれのwidthを10emにしました。
Div2.jpg
この時点では、h1要素とa要素の中身は中央寄せになりましたが、a要素自体は左に寄っています。これを真ん中に持ってくるためにdisplay:flex;を召喚します。

html
    <div id="felxcontainer">
        <h1>ノベルゲーム!</h1>

        <a href="">続きから</a>
        <a href="">最初から</a>
        <a href="">環境設定</a>
    </div>
css
#flexcontainer{
    display:flex;
    flex-flow: column nowrap;
    align-items:center;
    position:absolute;
    top:0;bottom:0;left:0;right:0;
}

すると
StartMenu3.jpg
無事真ん中に来ました。

3.背景がなんか寂しいなぁ…。

というわけでネットのフリー画像を背景に指定。

css
body{
    background:url("image/TopImage.jpg");
    margin:0;
    padding:0;
    position:absolute;
    top:0; bottom:0; left:0; right:0;
}

StartMenu4.jpg

全体的に上に寄っているので、h1とaの親要素(#flexcontainer)のcssに、justify-content:center;を追加します。すると以下の通り全体が真ん中に来ます。
StartMenu5.jpg

4.あとはこまごま調整して…

最終的にはこんな感じになりました。
StartMenu6.jpg

html
<body>

    <div id="flexcontainer">
        <h1>ノベルゲーム!</h1>
        <div>
            <a href="">続きから</a>
            <a href="">最初から</a>
            <a href="">環境設定</a>            
        </div>
    </div>
</body>
css
*{
    text-decoration:none;
    color:black;
}
body{
    background:url("image/TopImage.jpg");
    margin:0;
    padding:0;
    position:absolute;
    top:0; bottom:0; left:0; right:0;
}
#flexcontainer{
    display:flex;
    flex-flow: column nowrap;
    align-items:center;
    justify-content: center;
    position:absolute;
    top:0;bottom:0;left:0;right:0;
}
#flexcontainer div{
    border:2px solid white;
    border-radius:5px;
}
h1{
    margin:0;
    color:white;
    font-size:11vw;
    text-align: center;
}
a{
    color:white;
    display:block;
    text-align:center;
    font-size:2.5vw;
    line-height:2em;
    width:10em;
}
a:hover{
    background-color:rgba(255,255,255,.5);
}

根気が残っていれば次回以降はゲームの中身の部分を作っていく予定です。


参考サイト

  • PAKUTASO(ここのフリー画像を使いました。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 数値入力時にtypeをnumberにしたのに数値として扱われず困った話

目的

  • 勉強の実施時間を記録するwebアプリ作成の際に数値のinputで詰まり、コミュニティの方に助けていただいた話をまとめる
  • そもそもセオリーを理解できていなかったので二度とこんなことない様にまとめる。
  • .to_iを使って数値に変換できることはなんとなく知識としてあったが定着していなかったのでまとめる。

目標

  • すでにDBに格納されている数値に入力数値を足してDBに格納する。
  • 不動小数点や符号などはとりあえず考えず前述の目標をクリアする。

結論

  • 教えていただいた現役エンジニアさんのお言葉「入力値はtype指定してもStringになってしまうので受け取った側で型を指定して変換する」

問題のコード

  • 下記に問題のコードの一部を抜粋する。

  • コントローラ

    def update
      @post = Post.find_by(id: params[:id])
      @post.study_time = @post.study_time + params[:study_time]
      @post.save
      redirect_to("/posts/#{@post.id}")
    end
    
  • ビュー

    <%= form_tag("/posts/#{@post.id}/update") do %>
      <p>今日つみかさねた時間</p>
      <input type="number" name="study_time">
      <input type="submit" value="今日のつみかさね登録">
    <% end %>
    

詰まったところまでの概要

  1. 前述の問題のコードにて「今日のつみかさね登録」ボタンを押したところ下記のエラーが出た。

    no implicit conversion of integer into string
    
  2. エラーの内容から足そうとしている数値の型があっていないことがわかった。

  3. 筆者はビューファイルのinputtype="number"を指定して入力型を数値にしようと試みたが同じエラーが出た。

  4. 解決しようと試みたがいろいろ試してくうちに混乱してしまった。

解決方法

  • コントローラで受け取った値の型を数値に変換すことにより問題は解決した。

正常動作したコード

  • 下記に教えていただいた内容を元に修正を行なったコードを記載する。

  • コントローラ

    def update
      @post = Post.find_by(id: params[:id])
      @post.study_time = @post.study_time + params[:study_time].to_i
      @post.save
      redirect_to("/posts/#{@post.id}")
    end
    
  • ビュー

    <%= form_tag("/posts/#{@post.id}/update") do %>
      <p>今日つみかさねた時間</p>
      <!-- type="number"だと0~9までの入力しか受け付けられないためおって修正が必要 -->
      <input type="number" name="study_time">
      <input type="submit" value="今日のつみかさね登録">
    <% end %>
    

反省

  • .to_iで数値に変換できることは知ってはいたが使いどころが理解できてなかった。
  • そもそもセオリーを理解できていなかった。
  • 今考えると諦めなければ自己解決できたかもしれない。

よかったこと

  • エラー文をコピペで解決することをしなかった。
  • エラー文から問題箇所を特定することができた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CSSサブグリッドで真のフレキシブルなレイアウトを実現する方法

2019年12月3日、Firefox71がリリースされ、このバージョンから CSS Subgrid が使用できるようになりました。
CSS Subgridは2016年来からW3CのWorking Draftによって勧告されていましたが、今回のFirefoxのアップデートによって遂にユーザーへ提供できるようになりました。
この記事では、CSS Subgridの何が我々をワクワクさせ、どのようにインタフェースの実装を変化させてくれるのかについて紹介したいと思います。

CSS Subgrid とは

CSS Gridのおさらい

CSS Subgridの説明の前に、簡単にCSS Gridのおさらいをします。
CSS Gridとは、2次元レイアウトをCSSを用いて簡潔に組むための仕組みを指します。
任意の要素にdisplay: grid;を適用することで、以下の画像のように対象の要素はグリッドコンテナーとして、グリッドコンテナーの子要素はグリッドアイテムとして扱われます。
Group.png

<ul style="display: grid;"> <!-- グリッドコンテナー -->
  <li>ぺんぎん</li> <!-- グリッドアイテム -->
  <li>あざらし</li> <!-- グリッドアイテム -->
  <li>らっこ</li> <!-- グリッドアイテム -->
</ul>

CSS Gridの問題点

CSS Gridを用いることで、グリッドアイテムの高さを柔軟に揃えることが可能となりました。
では、我々の戦いはGridの登場によって終わりを迎えたのでしょうか。

そんなことはありません。グリッドアイテムの中の要素に目を向けるとどうでしょう。
グリッドアイテムの中には画像やテキスト等の複数の要素を設ける必要があります。これらのテキストはコンテンツによって変化するため、実装時には様々な高さへ変化することを想定しなくてはいけません。

しかしながら、グリッドアイテムは以下の画像のように、中の要素の高さまでは揃えることができません。
Group 2.png

CSS Subgridの登場

この問題を解決してくれるのがCSS Subgridです。
詳細な実装方法は後述しますが、グリッドアイテム要素に対してgrid-template-columns: subgrid;grid-template-rows: subgrid;を指定することで、CSS Subgridを有効化させることができます。
有効化させることで、グリッドアイテムの中の要素をサブグリッドアイテムとして扱うことができ、アイテム毎に高さを可変させることが可能となります。

以下の例ではSubgridを用いてタイトル部分の高さを可変させています。Subgrid未適用時は高さがコンテンツ毎に異なっているのに対し、Subgrid適応時は高さが統一されてるかと思います。

未適用時 適用時 (Firefox 71)

Subgridを自在に操ることで、真のフレキシブルなレイアウトを簡潔に実現することが可能となります。

対応環境 (2019/12/07現在)

現在はFifefox 71~ のみ対応しています。
image.png
Subgrid | Can I Use...より

使い方

サンプル

(Firefox 71~で確認してみてください。)

実装方法

Subgridは以下のソースコードで対応することが可能です。

<ul class="gridContaienr">
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
  <li class="gridItem">
    <img src="https://via.placeholder.com/150" alt="">
    <h3>タイトル</h3>
    <p>テキスト</p>
    <a href="http://example.com/">リンク</a>
  </li>
</ul>
.gridContainer {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  grid-gap: 1em;
}

/* 以下の記述を追加 */
.gridContainer .gridItem {
  display: grid;
  grid-row: span 4;
  grid-template-rows: auto auto 1fr auto; /* fallback for non-supported browsers */
  grid-template-rows: subgrid;
}

まずは.gridItemdisplay: grid;を指定することでグリッドコンテナーとして扱う必要があります。
同時に、grid-template-rows: subgrid;を指定することで、グリッドコンテナーをサブグリッド化することができます。

こちらの例ではSubgridに対応していないブラウザ用のフォールバックとして、grid-template-rows: auto auto 1fr auto;を指定しています。
可変させる要素と固定させる要素を明示することで、Subgridに対応していないブラウザでも最低限のレイアウトを担保できるので、未サポートブラウザが多い現在はこちらの記述も必須でしょう。

終わりに

CSS SubgridはFlexやGridだけでは実現できなかったレイアウトを簡潔に実現できる力を秘めていると考えられます。
現在はFirefoxのみが対応していますが、今後より多くのメジャーなブラウザへの実装され、ユーザーへ提供できるようになることを願ってやみません。

参考サイト

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

CSSだけで動的サイトを作れるらしい!!

はじめに

最近まで深層学習の技術ブログを書いていたが、心機一転してWeb系の勉強に戻ることにした。
今までは安定を求めてAIを数ヶ月勉強していたけど面白くなかった。
やはり楽しいほうがいいと思ったので今回Web系に戻ろうと思う。

CSSだけで動的サイトを作る

今まで動的サイトといえばJavaScriptを使わないといけないと思っていたが、実はJavaScriptから提供された変形とアニメーションの機能がCSSにあるらしい。
聞くところによればJavaScriptよりも高速に動くらしいのでこれから是非使っていきたいと思う。

transformプロパティ

cssでtransformプロパティを使うことで、移動・拡大縮小・回転・傾斜の変形を行うことができる。
これらの変形を行うには、transformプロパティで、各トランスフォーム関数をして営してあげることで行うことができる。

transelate(x軸の移動,y軸の移動)
translate関数を使うことで、x軸y軸の移動を行うことができる。
上の様にx軸とy軸の移動する距離を指定してあげることで要素を移動することができる。

scale(x軸方向の倍率,y軸方向の倍率)
scale関数を使うことで要素のx軸y軸方向の拡大縮小が可能です。

rotate(回転角度)
rotate関数で要素を回転させることができます。
どれだけ回転させるかは、角度を指定することで決められます。

skew(x軸の傾斜角度,y軸の傾斜角度)
skew関数で要素に傾斜をつける変形を行うことができます。

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

Sortable.jsを使ってスパイダーソリティアを作ってみた

はじめに

現在SIerからWebエンジニアへの転職活動中で、ポートフォリオの一つとして
私の好きなゲームであるスパイダーソリティアをつくってみることにしました。
(スパイダーソリティアのルールはこちらから)

ソース:Git Repo

プレイ:こちらから
※レスポンシブ対応はしていません(PCのみ)

イメージ

スパイダーソリティア.PNG

終わりに

  • 作成期間は約1か月ほどかかりました
  • アルゴリズムや、一からのモノ作りを学ぶことができました
  • SortableJSは結構いろいろな動作をさせることができました

途中ほんとうに挫折しかけましたがなんとか完成させることができたのでとても良かったです!

<使用技術>
HTML/CSS/JavaScript/SortableJs/Bootstrap/JQuery etc

<参考にしたサイト>
【jQueryUIを使わずにドラッグ&ドロップを実装したい】Javascriptライブラリ「Sortable」を使ってみた

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

HTML CSS Flexboxとは

要素を並べるのにfloat: left;使ってるけど、他にも並べる方法ないかなあ:thinking:

参考サイト→https://www.webcreatorbox.com/tech/css-flexbox-cheat-sheet#flexbox1
随時更新します

Flexboxを使ってみよう

FlexboxとはFlexible Box Layout Moduleの略。左から順に並べられるのは勿論、右からや下からなど自由に要素をレイアウト出来る。

基本

flex_box01.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ブロックとインライン</title>
    <link rel="stylesheet" href="css/flex_box01.css">
  </head>
<body>
  <div class="container01">
    <div class="item">
      アイテム&ensp;1
    </div>
    <div class="item">
      アイテム&ensp;2
    </div>
    <div class="item">
      アイテム&ensp;3
    </div>
    <div class="item">
      アイテム&ensp;4
    </div>
  </div>
</body>
</html>
flex_box01.css
.container01 {
    display: flex;
}
.item {
    margin: 10px 10px;
    padding: 2px 4px;
    background: #f8dcdc;
}

20191129_Qiita01.png
display: flex;を親要素に適用し、子要素が横に並んだ。

Flexboxで親要素に指定するプロパティ

htmlは上と同じ。

flex-direction: row;

flex_box02.css
.container01 {
    display: flex;
    flex-direction: row;
}
.item {
    ~省略~
}

20191129_Qiita02.png
右から左へ並ぶ

flex-direction: row-reserve;

flex_box03.css
.container01 {
    display: flex;
    flex-direction: row-reverse;
}
.item {
    ~省略~
}

20191129_Qiita03.png
左から右へ並ぶ

flex-direction: column;

flex_box04.css
.container01 {
    display: flex;
    flex-direction: column;
}
.item {
    ~省略~
}

20191129_Qiita04.png
上から下へ並ぶ

flex-direction: column-reverse;

flex_box05.css
.container01 {
    display: flex;
    flex-direction: column-reverse;
}
.item {
    ~省略~
}

20191129_Qiita05.png
下から上へ並ぶ

flex-wrap: nowrap;

説明のために数を増やした

flex_box02.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ブロックとインライン</title>
    <link rel="stylesheet" href="css/flex_box.css">
  </head>
<body>
  <div class="container02">
    <div class="item">
      アイテム&ensp;1
    </div>
    <div class="item">
      アイテム&ensp;2
    </div>
    <div class="item">
      アイテム&ensp;3
    </div>
    <div class="item">
      アイテム&ensp;4
    </div>
    <div class="item">
      アイテム&ensp;5
    </div>
    <div class="item">
      アイテム&ensp;6
    </div>
    <div class="item">
      アイテム&ensp;7
    </div>
    <div class="item">
      アイテム&ensp;8
    </div>
    <div class="item">
      アイテム&ensp;9
    </div>
    <div class="item">
      アイテム&ensp;10
    </div>
  </div>
</body>
</html>
flex_box06.css
body {
    ~省略~
}
.container02 {
    margin: 10px auto;
    display: flex;
    flex-wrap: nowrap;
}
.item {
    ~省略~
}

20191129_Qiita06.png
折り返しなしで一行で並ぶ

flex-wrap: wrap;

flex_box06.css
body {
    ~省略~
}
.container02 {
    margin: 10px auto;
    display: flex;
    flex-wrap: wrap;
}
.item {
    ~省略~
}

20191129_Qiita07.png
子要素が折り返して複数行になり、上から下へ並ぶ

flex-wrap: wrap-reverse;

flex_box07.css
body {
    ~省略~
}
.container02 {
    margin: 10px auto;
    display: flex;
    flex-wrap: wrap-reverse;
}
.item {
    ~省略~
}

20191203_Qiita01.png
子要素が折り返して複数行になり、下から上へ並ぶ

flex-flow: ;

flex_box08.css
.container02 {
    margin: 10px auto;
    display: flex;
    flex-flow: row-reverse nowrap;
}

flex-directionflex-wrapを一行で指定できるプロパティ。

justify-content: flex-start;

flex_box09.css
.container02 {
    margin: 10px auto;
    display: flex;
    justify-content: flex-start;
}

20191203_Qiita02.png
10個だと分かりにくかったので5個にした。親要素に空いているスペースがあるとき、子要素を水平方向のどの位置に置くか指定
flex-startは左揃えになる。

justify-content: flex-end;

flex_box10.css
.container02 {
    margin: 10px auto;
    display: flex;
    justify-content: flex-end;
}

20191203_Qiita03.png
flex-endは右揃えになる

justify-content: flex-center;

flex_box11.css
.container02 {
    margin: 10px auto;
    display: flex;
    justify-content: flex-center;
}

20191203_Qiita04.png
flex-centerは中央揃えになる

justify-content: space-between;

flex_box12.css
.container02 {
    margin: 10px auto;
    display: flex;
    justify-content: space-between;
}

20191203_Qiita05.png
最初の子要素を左端、最後の子要素を右端に配置し、残りの要素は均等に間隔をあけて配置

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

box-shadowで月の表現

最終成果物

これです。
ぽいですね。
これがbox-shadowプロパティで実現できます。

moon.gif

実装

土台になるhtmlの用意

さっくりと。

moon.html
<!DOCTYPE html>
<html lang ="ja">
<head>
    <link rel="stylesheet" href="../css/moon.css">
</head>
<body>
    <main class="stage">
        <div class="moon"></div>
    </main>
</body>
</html>

CSS

こちらもさっくりと。
解説はあとあと。
stageはただの背景なのでそんなに気にしなくていいです。

moon.css
/**
* stage
*/
.stage {
  position: absolute;
  width: 100%; height: 100%;
  background-color: rgb(228, 217, 210);
  display: flex;
  justify-content: center;
  align-items: center;
}
.stage:before,
.stage:after { position: absolute; content: ""; display: block; }
.stage:before {
  top: 20px; left: 20px;
  width: calc(100% - 40px); height: calc(100% - 40px);
  border: solid 5px #6e5c60;
  border-radius: 30px;
  box-sizing: border-box;
  opacity: 0.3;
}

/**
* moon
*/

.moon {
  width: 500px;
  height: 500px;
  border-radius: 100%;
  animation: anime 5s linear infinite;
}

@keyframes anime{
  from{
    box-shadow: none;
  }
  to{
    box-shadow: 500px -200px 0 0 rgb(254, 228, 137) inset;
  }
}

ちょっとだけ解説

実際のイメージとは逆かもですが、黄色の明るい部分がbox-shadowで表現されている部分です。
keyframesで定義されている通り、影がない状態から影がある状態にアニメーションさせています。
円形に別のオブジェクトを重ねようとするとどうしても線形な変化になってしまうので、自身に影をつけることで変化させます。
当然外側に影をつけても月にはならないので内側に変化させるためにinsetをbox-shadowにつけるのを忘れずに。

まとめ

box-shadowを内側につけるのは何かと使う場面がありそうですね。
意識していないと忘れてしまいそうなプロパティなのでたまに使ってあげましょう。

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

初学者が手っ取り早くコーディング練習する方法

こんにちは、たか(@HighHawk5)です。

普通はローカル(自分のパソコン)に開発環境を用意してコーディングしますが、面倒だったりできない場合に便利なのがクラウドIDE。ブラウザ上で簡単にコーディング&表示確認ができます。

今回は数あるクラウドIDEのなかでも一番ライトに使えるCODEPENをご紹介します。

メリット
・開発環境の構築が不要
・色々なエンジニアの作品を参考にできる

これは私のpenですが、このようにコーディング&表示確認が一画面でできて便利ですよね!
右上のCODEPENアイコンから本サイトに移動し、メニューの「Fork」をクリックすると、私の作品をあなたのワークスペースにコピーしてコーディングすることもできます。模写がボタン一発で!

Vue.jsはこちらのサンプルなんてどうでしょう?
https://codepen.io/JavaScriptJunkie/pen/YzzNGeR

コーディングの上達方法は、見本のコードを模写してイジり倒すこと!

では、より良いエンジニアライフを!

おしまい

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

初学者が簡単にコーディング練習する方法

こんにちは、たか(@HighHawk5)です。

普通はローカル(自分のパソコン)に開発環境を用意してコーディングしますが、面倒だったりできない場合に便利なのがクラウドIDE。ブラウザ上で簡単にコーディング&表示確認ができます。

今回は数あるクラウドIDEのなかでも一番ライトに使えるCODEPENをご紹介します。

メリット
・開発環境の構築が不要
・色々なエンジニアの作品を参考にできる

これは私のpenですが、このようにコーディング&表示確認が一画面でできて便利ですよね!
右上のCODEPENアイコンから本サイトに移動し、メニューの「Fork」をクリックすると、私の作品をあなたのワークスペースにコピーしてコーディングすることもできます。模写がボタン一発で!

Vue.jsはこちらのサンプルなんていかがでしょう?

コーディングの上達方法は、見本のコードを模写してイジり倒すこと!

では、より良いエンジニアライフを!

おしまい

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

FloatとFlexboxについて

はじめに

中一日でAdventcalendarの日がまわってQiita!
今回は、自分がいまいち理解できなかったFloatとFlexboxの違いについてまとめてみました。

本題

みなさんは、要素を横並びにするときに何を使っていますか??
FloatFlexbox,FloatにFlexboxなどなどさまざまな方法があると思います。
ということで今回は、FloatとFlexboxって、なにがちがうの?どっちの方を使ったほうがいいのかという2つの観点に目を向けて記事を書いていこうと思います。

今回はFloat・Flexboxを用いて下記のような表示をさせるためにコードを記述していきます。

advent.png

Float

 <body>
        <style>
<!-- ブラウザが持っているCSSをリセットするため -->
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            .cleafix::after {
                content: "";
                display: block;
                clear: both;
            }
            .test {
                width: 400px;
                height: 300px;
                margin: 0 auto;
                padding: 5px;
                background-color:aqua;
            }
            .box_A {
                width: 100px;
                height: 100px;
                margin-right: 5px;
                background-color: blue;
                float: left;
            }
            .box_B {
                width: 100px;
                height: 100px;
                margin-right: 5px;
                background-color: yellow;
                float: left;
            }
            .box_C {
                width: 100px;
                height: 100px;
                margin-right: 5px;
                background-color: red;
                float: left;
            }
            footer{
                width: 400px;
                height: 100px;
                margin: 0 auto;
                background-color: purple;
            }
        </style>
        <div class="test clearfix">
            <div class="box_A"></div>
            <div class="box_B"></div>
            <div class="box_C"></div>
        </div>
        <footer></footer>

    </body>

    Points

  1. .clearfix::after{}により、回り込みを防ぐ

  2. `::after` セレクタ要素の直後にスタイルや要素を追加するもの

  3. `content: "";` floatされた要素の親要素の直後に空白の要素を挿入

  4. `display: block;`: contentプロパティによって挿入された空白を横いっぱいに伸ばし、壁のようにする。

  5. `clear:both;`: displayプロパティによって作成れた壁にfloatの回り込みを解除するための機能を与える。

  6. `float:left;`: floatさせたい要素にfloatプロパティを記述する。

以上の2点により、Floatプロパティを用いて、要素を横並びにすることができます。

Flexbox

 <body>
        <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            .f-container {
                width: 400px;
                height: 300px;
                margin: 0 auto;
                padding: 5px;
                display: flex;
<!-- conteiner(親要素に使用できるプロパティを紹介したいがために書いたおまけ -->
                flex-flow: row wrap;
                background-color: aqua;
            }
            .item_A {
                width: 100px;
                height: 100px;
                margin-right: 5px;
                background-color: blue;
            }
            .item_B {
                width: 100px;
                height: 100px;
                margin-right: 5px;
                background-color: yellow;
            }
            .item_C {
                width: 100px;
                height: 100px;
                background-color: red;
            }
            footer {
                width: 400px;
                height: 100px;
                margin: 0 auto;
                background-color: purple;
            }
        </style>
        <div class="f-container">
            <div class="item_A"></div>
            <div class="item_B"></div>
            <div class="item_C"></div>
        </div>
        <footer></footer>
    </body>

Points

  • Floatでは、小要素にFloatプロパティを書き、回り込みを防ぐために、`.clearfix::after{}`を記述していましたが、Flexboxでは、親要素に`display:flex`と記述するだけで、Floatと同じような表示ができます。

  • 親要素に`flex-flow: row wrap;`という記述をしていますが、これは、itemの並び順と折返しを一括指定しています。今回表示させたいものには、直接関係はありませんが、親要素のコンテナに使用できる便利なプロパティとして紹介させていただきました。

詳しい情報はこちらから

まとめ

近年では、上記で記したようにflexboxのほうが、非常に簡単に要素を横並びにすることができます。
みなさんもぜひ、Flexboxを使って楽にコードを書いてみてはいかがでしょうか。

参考資料

こちら(flexbox):https://webdesign-trends.net/entry/8148

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