【Rails】レスポンシブデザイン導入してみる

こんばんは！引き続き某フリマアプリ開発が続いています。今日はレスポンシブデザインについて学習した事をまとめてみました！

## 環境

rails 5.2.3
ruby 2.5.1

## こんな感じにしたい

***レスポンシブデザインとはPC以外の端末、スマホやタブレットから閲覧してもレイアウトがデバイスの画面サイズに適したデザインにできます。webサービスをモバイルフレンドリーにする方法です***

![demo](https://gyazo.com/ce858ae337d67924a0e3f2bc44c1dd2e/raw)

## 作成手順

#### サイドメニュー部分をまず作ります

```haml:sidemenu.htm.haml
.sidemenu
  = search_form_for @q, url:search_result_items_path do |f|
  .search-sort
    .form-group
      .search-select-wrap
        .icon.fas.fa-chevron-down
        = f.select(:sorts, { '並び替え': 'id desc', '価格の安い順': 'price asc', '価格の高い順': 'price desc', '出品の古い順': 'updated_at asc', '出品の新しい順': 'updated_at desc' }, { selected: params[:q][:sorts] }, { onchange: 'this.form.submit()'} )
    .search-dropdown-content.search-extend
      %h3.visible-large
        詳細検索
      .search-form-group
        %lavel
          %i.fas.fa-plus
          %span
            キーワードを追加する
        = f.search_field:name_cont, placeholder:"商品名など", class:"search-input-default"
      .search-form-group
        %lavel
          %i.fas.fa-list-ul
          %span
            カテゴリーを選択する
          .search-select-wrap
            .icon.fas.fa-chevron-down
            = f.fields_for :category do |category|
              = category.collection_select :category_id_eq, @parents, :id, :name, {prompt: "全て"}, {class: "search-input-default select"}
      .search-form-group
        %lavel
          %i.fas.fa-tags
          %span
            ブランド名から探す
            %input.search-input-default{ name: "keyword", placeholder: "まだ実装できてない", type: "text", value: ""}/
      .search-form-group
        %lavel
          %i.fas.fa-expand
          %span
            サイズを指定する
          .search-select-wrap{"data-search" => "parent"}
            .icon.fas.fa-chevron-down
            %select.search-input-default.select{:name => "size_group"}
              %option{:value => ""} まだ実装できてない
      .search-form-group
        %lavel
        %i.fas.fa-coins
        %span
          価格
        .search-select-wrap
          .icon.fas.fa-chevron-down
          %select.search-input-default.select
            %option{value: "def0"}
              選択して下さい
        .search-select-wrap.half
          = f.number_field:price_gteq, placeholder: "¥Min", class:"search-input-default price", id: "min-price"
          %span ~
          = f.number_field:price_lteq, placeholder: "¥Max", class:"search-input-default price", id: "max-price"
      .search-form-group.clearfix
        %lavel
          %i.fas.fa-star
          %span
            商品の状態
        %div.form-group__check
          .checkbox
            .checkbox__lavel
      .search-form-group
        %label
          %i.fas.fa-truck-moving
          %span
            配送料の負担
      .search-form-group
        %label
          %i.fas.fa-shopping-cart
          %span
            販売状況
      .search-extend-btn
        = f.button "クリア", type: :reset, class:"btn-default btn-gray search-btn"
        = f.submit "完了", class: "btn-default btn-red search-btn"
```
まだ完成していないので中途半端なコードお許し下さい。ポイントは`gem 'ransack'ソート機能部分`なのですが、今回はレスポンシブについての記事なので別記事でまた書きたいと思います。

```scss:sidemenu.scss
@media screen and (min-width: 1068px) {
//この中のcssプロパティは画面サイズが1068px以上の時のみ適応します
//以下一部だけ抜粋
  .search-extend-btn {
    display: flex;
  }
  .btn-default.btn-gray.search-btn {
    width: 42%;
    margin-right: 25px;
    outline: 0;
  }
  .btn-default.btn-red.search-btn {
    width: 42%;
  }
```
上記のscssは`画面が1068px以上の場合のみ`適応されるプロパティになるので以下の写真のボタンになります。
![スクリーンショット 2019-09-20 17.30.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428016/3386cf03-f6dd-08cf-ad90-5692303cd140.png)

#### 画面縮めた時用のsidemenuを準備
先項では1068px以上の時のsidemenuなので次は`1068px以下の画面用のsidemenu`を作ります。

```haml:responsive.html.haml
.responsive-sidemenu
  .hidden-select-box
    %i.hidden-select-box__icon.fas.fa-exchange-alt
    .hidden-select-box__name 並び替え
    %select.hidden-select-box__left-search
      %option{value: ""}
      %option{value: ""}
        これはハリボテです
  .hidden-select-box
    %i.hidden-select-box__icon.fas.fa-search
    .hidden-select-box__name 詳細検索
    %button.hidden-select-box__search-box
```

```scss:sidemenu.scss
//以下一部だけ抜粋
.hidden-select-box {
  width: 340px;
  position: relative;
  display: flex;
  &__icon.fas.fa-exchange-alt {
    position: absolute;
    right: 165px;
    top: 35%;
    color: #aaa;
    font-size: 14px;
    -webkit-transform: rotate(90deg);
    transform: rotate(90deg);
  }
  &__icon.fas.fa-search {
    position: absolute;
    right: 150px;
    top: 20%;
    color: #aaa;
    font-size: 14px;
  }
  &__name {
    position: absolute;
    right: 140px;
    top: 60%;
  }
  &__left-search {
    background: #fff;
    outline: 1px solid #ccc;
    width: 320px;
    font-size: 14px;
    height: 60px;
    padding: 10px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
  }
  &__search-box {
    background: #fff;
    outline: 1px solid #ccc;
    width: 320px;
    font-size: 14px;
    height: 60px;
    padding: 10px;
  }
}

@media screen and (min-width: 1068px) {
  .search-extend-btn {
    display: flex;
  }
  .btn-default.btn-gray.search-btn {
    width: 42%;
    margin-right: 25px;
    outline: 0;
  }
  .btn-default.btn-red.search-btn {
    width: 42%;
  }
```
`@mediaの外に書いてあげます`。すると以下の画像のような検索ボックスを作れます。

![スクリーンショット 2019-09-20 17.40.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428016/7bd940db-72a0-49bd-7b31-4d16e6757883.png)

#### このままだとこんな感じ

![スクリーンショット 2019-09-20 17.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428016/12746115-a930-8728-9d39-faad12eb3ebc.png)

1068px以上に画面を広げた時に本来は左側のsidemenuのみ表示したいんですが、`前項で作った1068px以下の時用responsive-sidemenu`もこんにちはしてしまいます。
ブレイクポイント前後でレイアウトの配置が変わるレスポンシブは実装した事がありましたが、`ある要素が消えて新しい要素を出現させる`という実装は初めてだったのでここで躓きました。

## 今回の解決方法 !important

「!important」は、CSSに非常に強く指示を出せる効果的手法ですが、乱用は禁物です。あくまで、最後の手段と考えてください。乱用によって、逆にCSSが効かなくなることがあることは覚えておいてください。
>CSSの優先順位を理解しよう（!importantの使い方も）
https://creive.me/archives/14805/

今回は`!important`使いました。***display: none;とvisibility: visible;を使ってみたが表示・非表示の切り替えがうまくでませんでした。***
`display: none;`を使うとレスポンシブのブレイクポイント切り替え前後ともに表示されない。また`visibility: hidden;`も使ってみたのですが、これは`display:none;`と違い要素が消えるわけではなく見えなくなるので、見えない要素がそこに残っています。今回の実装では使えません。

## 完成コード

```scss:sidemenu.scss

.sidemenu {
  display: none !important;
}
//1068px以下の画面サイズの時.sidemenu配下にいる全ての要素は消えてくれます
.responsive-sidemenu {
  display: flex !important;
}
//1068px以下の画面サイズの時.responsive-sidemenu配下にいる全ての要素が表示されます

//以下一部だけ抜粋
.hidden-select-box {
  width: 340px;
  position: relative;
  display: flex;
  &__icon.fas.fa-exchange-alt {
    position: absolute;
    right: 165px;
    top: 35%;
    color: #aaa;
    font-size: 14px;
    -webkit-transform: rotate(90deg);
    transform: rotate(90deg);
  }
  &__icon.fas.fa-search {
    position: absolute;
    right: 150px;
    top: 20%;
    color: #aaa;
    font-size: 14px;
  }
  &__name {
    position: absolute;
    right: 140px;
    top: 60%;
  }
  &__left-search {
    background: #fff;
    outline: 1px solid #ccc;
    width: 320px;
    font-size: 14px;
    height: 60px;
    padding: 10px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
  }
  &__search-box {
    background: #fff;
    outline: 1px solid #ccc;
    width: 320px;
    font-size: 14px;
    height: 60px;
    padding: 10px;
  }
}

@media screen and (min-width: 1068px) {
  .responsive-sidemenu {
  display: none !important;
  }
//1068px以上の画面サイズの場合は.responsive-sidemenu配下にいる全ての要素は消えてくれます
  .sidemenu {
    display: block !important;
  }
//1068px以上の画面サイズの場合は.sidemenu配下にいる全ての要素は表示されます
  .search-extend-btn {
    display: flex;
  }
  .btn-default.btn-gray.search-btn {
    width: 42%;
    margin-right: 25px;
    outline: 0;
  }
  .btn-default.btn-red.search-btn {
    width: 42%;
  }
```

## ポイントは...

```scss
display: block !important;
//値はinline,inline-block,flexなど表示の仕方で変えられます
display: none !important;
```
この２つを表示・非表示したい要素に指定してあげます。

## まとめ

某フリマサイトはPC/タブレット/スマホの3画面に対応しているので本物に近づける為にはブレイクポイントを2つ作る必要がありそうです。ただ開発期間中にそこまでこだわる事は時間的に難しいので、個人アプリではぜひ実装してみたいと思います！

#### 終わり