vertical-alignの使い方と別の実装方法について

こんにちは、エンジニアの井戸田です。

先日 vertical-align ではまり、検索してみると予測変換で vertical-aling 効かない と出てくるので、結構皆さんもはまっているんだなと感じました。 なので今回は僕もはまったcssのプロパティである、 vertical-align の値・使い方や、垂直方向の調整の別の実装方法を紹介したいと思います。

コードについて、htmlはslim、cssはscssを使用しているので注意してください。

vertical-alignの説明

vertical-align は行内のテキスト、画像の垂直方向の揃え位置を指定するプロパティです。 vertical-align は適用できるのが、 inline要素テーブルセル です。なので divタグpタグ などの ブロック要素 に対して vertical-align を指定してもうまくいきません。
divタグpタグvertical-align を指定したい時は diplay: inline や, display: table-cell , diplay: inline-block を指定し、要素自体を変更する必要があります。

説明
baseline 適当した要素のベースラインを親要素のベースラインに合わせる(初期値)
top 適用した要素の上端を、行ボックスの上端に合わせる
middle 適用した要素の中心を、親要素の中心に揃える
bottom 適用した要素の下端を、行ボックスの下端に合わせる
text-top 適用した要素の上端を、親要素の文字の上端に合わせる (テーブルセルへの指定はできない)
text-bottom 適用した要素の上端を、親要素の文字の下端に合わせる (テーブルセルへの指定はできない)
super 上付き文字 (テーブルセルへの指定はできない) 
sub 下付き文字 (テーブルセルへの指定はできない)
pxなどの単位 px, emなどの単位を使用しての指定(ベースラインが揃った状態を0、正の値は上方向、負の値はした方向になる)
  • 初期値が baseline なのですが、画像などは baseline を持たないため、下端が親要素のベースラインに揃えられます。
  • middleとは、フォントの場合 0.5ex 。小文字の「x」の半分高さです。

toptext-topbottomtext-bottombaselinetext-bottom の違いについて、勘違いしやすいので下記にまとめておきます。

top と text-topの違い

.verticalAlign.verticalAlign-top
  span.example
    | Example
    span.parent
      | parent
      span.child
        | top

.verticalAlign.verticalAlign-textTop
  span.example
    | Example
    span.parent
      | parent
      span.child
        | text-top
.verticalAlign {
  margin: 0 0 8px 0;
  background-color: #f93;

  &-top {
    .child {
      vertical-align: top;
    }
  }

  &-textTop {
    .child {
      vertical-align: text-top;
    }
  }
}

.example {
  background-color: #fd7c79;
  font-size: 5rem;
}

.parent {
  background-color: #33cfff;
  font-size: 2.5rem;
}

.child {
  background-color: #24ff18;
  font-size: 1rem;
}

f:id:cluex-developers:20160909205157p:plain

上が top で 下が text-top になります。
text-top は親要素の文字の上端(一番高い場所)を基準とします。なので上端を基準として配置することが可能です。
top は適用した要素の上端を、行ボックスの上端に合わせるため上記のような表示になります。

bottom と text-bottomの違い

.verticalAlign.verticalAlign-bottom
  span.example
    | Example
    span.parent
      | parent
      span.child
        | bottom

.verticalAlign.verticalAlign-textBottom
  span.example
    | Example
    span.parent
      | parent
      span.child
        | text-bottom
.verticalAlign {
  margin: 0 0 8px 0;
  background-color: #f93;

  &-bottom {
    .child {
      vertical-align: bottom;
    }
  }

  &-textTop {
    .child {
      vertical-align: text-bottom;
    }
  }
}

// 省略 以下はtopとtext-topと指定の仕方は同じです。

f:id:cluex-developers:20160909205407p:plain

上が bottom で下が text-bottom になります。
text-bottom は親要素の文字の下端(ディセンター文字の下端)を基準として配置することが可能です。
また bottom は適用した要素の下端を、行ボックスの下端に合わせるため上記のような表示になります。

baseline と text-bottom

次は baselinebottom-text に対してどのような違いがあるのか、説明します。

.verticalAlign.verticalAlign-baseline
  span.example
    | Example
    span.parent
      | parent
      span.child
        | baseline

.verticalAlign.verticalAlign-textBottom
  span.example
    | Example
    span.parent
      | parent
      span.child
        | text-bottom
.verticalAlign {
  margin: 0 0 8px 0;
  background-color: #f93;

  &-baseline {
    .child {
      vertical-align: baseline;
    }
  }

  &-textBottom {
    .child {
      vertical-align: text-bottom;
    }
  }
}

// 省略 以下はtopとtext-topと指定の仕方は同じです。

f:id:cluex-developers:20160909205017p:plain

上記を見てみるとどのような違いがあるのか迷うと思うのですが、親要素( .parent )を対して line-height を入れてみると違いが良く分かります。

.verticalAlign.verticalAlign-baseline
  span.example
    | Example
    span.parent
      | parent
      span.child
        | baseline

.verticalAlign.verticalAlign-textBottom
  span.example
    | Example
    span.parent
      | parent
      span.child
        | text-bottom
.verticalAlign {
  margin: 0 0 8px 0;
  background-color: #f93;
  
  &-baseline {
    .child {
      vertical-align: baseline;
    }
  }
  
  &-textBottom {
    .child {
      vertical-align: text-bottom;
    }
  }
}

.example {
  background-color: #fd7c79;
  font-size: 5rem;
}

.parent {
  background-color: #33cfff;
  font-size: 2.5rem;
  line-height: 2; // ← 追加
}

.child {
  background-color: #24ff18;
  font-size: 1rem;
}

f:id:cluex-developers:20160909205503p:plain

.parent に対して line-height: 2; を指定すると、 baseline は親のフォントのベースライン(基準線)に合わせるので、ズレは生じません。ただ text-bottom は親の要素の文字の下端に合わせるので、ズレが生じてしまいます。
上記の例の様に親の要素で line-height (や height などの縦幅調整をするプロパティ)を指定している時は注意が必要です。

(実際に実装する時には 初期値が baseline なので、 vertical-aling: baseline; の指定は必要ありません。)

ブロック要素への対応

テーブルセルとdisplay: table-cellの使い方

テーブルセルとは tableタグ で使用する tdタグ , thタグ のことです。こちらの要素に対しても vertical-align を使用すことができます。但し text-top , text-bottom , super , sub は指定することができません。 display: table-cell での実装方法は下記の様になります。下記の例では .block を垂直方向に中央揃えにしています。

.tableCell
  .block
    | block
.tableCell {
  display: table-cell;
  height: 100px;
  background-color: #f93;
  vertical-align: middle;
}

f:id:cluex-developers:20160909205532p:plain

block要素 に対して vertical-align を使用する場合には、垂直方向の調整をしたいタグの親要素に対して display: table-cell , vertical-align: ◯◯ を指定することで、使用することができます。 ただ表に関係ない要素に display: table-cell を指定するのはバットな気がしますね。

display: inline-block

display: table-cell を使用しないで display: inline-block を使用する方法もあります。inline-block要素 とは inline要素block要素 を兼ね備えた要素です。下記の例では2つの inline-block要素 を垂直方向に中央揃えにしています。

.block
  .inlineBlock1
    | inlineBlock1
  .inlineBlock2
    | inlineBlock2
.inlineBlock1 {
  display: inline-block;
  height: 8rem;
  background-color: #fd7c79;
  font-size: 2rem;
  vertical-align: middle;
}

.inlineBlock2 {
  display: inline-block;
  background-color: #33cfff;
  font-size: 2rem;
  vertical-align: middle;
}

f:id:cluex-developers:20160909205049p:plain

block要素 に対して display: inline-blockvertical-align: ◯◯ を指定することで、使用することができます。 inline-block要素inline要素 で異なるのが、 inline-block要素 の場合は横幅・縦幅が指定が可能なので、その分 inline要素 より使い易いかも知れません。

block inline inline-block の違いについては、また別の機会に詳しく話したいと思います!

vertical-alingを使用しないで垂直方向を調整する方法として

  • line-height
    line-height を使用して、親要素のheightに調整する。なんとなくバットな調整方法だと思います・・・。
  • position
    親のblock要素に対して position: relative 、子要素に対して postion: absolute を指定する。
    ただ垂直方向の中央揃えにしたいと思っていても、 postion:absolute は指定した要素の本来の位置からの相対位置なので top: 50% という指定をしていても、その要素の上端が真ん中にきてしまうので、 top: 50% ではなく調整する必要があります。

上記2つを挙げましたが、それぞれ調整が難しいと思います。そこで僕個人がおすすめしたいのが FlexBox を使用する方法です。

FlexBoxを使用し垂直方向を調整する

FlexBox とは「Flexible Box Layout Module(フレキシブルボックスレイアウトモジュール)」のことで、要素をFlexコンテナというボックス内にフレキシブルで簡単に整列する方法です。

FlexBoxに対応しているブラウザは下記のようになります。

f:id:cluex-developers:20160909210303p:plain

参考) Can I use... Support tables for HTML5, CSS3, etc

  • IE11から正式対応。
  • safariには -webkit- のベンダープレフィックス必要のようです。

垂直方向の調整をするために align-items 又は align-self というプロパティを使用します。

align-items と align-self

  • align-items
    flexコンテナに対して指定することで、コンテナ内のすべてflexアイテム(子要素)に対して、同じ位置に調整します。
  • align-self
    flexアイテムに対して指定することで、個別に位置を調整します。
説明
baseline flexアイテム内の文字のベースラインを揃える。 最初のflexアイテムのbaselineに揃うようです。
flex-start flexアイテムの上端を揃える( flex-directioncolumncolumn-reverse の場合は右側を揃える)
flex-end flexアイテムの下端を揃える( flex-directioncolumncolumn-reverse の場合は右側を揃える)
center 適用した要素の中心を、親要素の中心に揃える( flex-directioncolumncolumn-reverse の場合は横幅の中央を揃える)
stretch レックスアイテムの高さを揃える( flex-directioncolumncolumn-reverse の場合は横幅を揃える)

下記の例では、 align-items: center を使用して実装してます。

.flexBox
  .flexItem1
    | flexItem1
  .flexItem2
    | flexItem2
  span.flexItem3
    | flexItem3
.flexBox {
  display: flex;
  align-items: center;
}

.flexItem1 {
  background-color: #fd7c79;
  height: 200px;
}

.flexItem2 {
  background-color: #33cfff;
  height: 80px;
}

.flexItem3 {
  background-color: #24ff18;
  height: 160px;
}

f:id:cluex-developers:20160909205040p:plain

.flexBox に対して display: flex , align-items: center を指定することで、flexコンテナ内の全てのflexアイテムが垂直方向に中央揃えになります。 このように簡単に垂直方向を調整することができるので、ブラウザの対応に気をつけなければいけませんが、 FlexBox はとても便利です。

もし vertical-align での調整が難しい場合には、 FlexBoxの導入をぜひ検討してみてください。弊社が運用しているmamanokoでも flex を多用してます。

余談

株式会社Cluexではエンジニアの方を探しています!

cluex.co.jp

GeocoderとGeokitを使用して、現在地周辺検索を行う機能を実装してみた

こんにちは、エンジニアの神山です。最近大豆製品ばっかり食べています。

今回はWebサービスでよく見かける、現在地周辺検索を行う機能の実装について書きました。

例えば現在地から半径2km内にあるレストランを検索したり、現在地より最寄りの駅を探したりできる機能です。

今回使用したGemは、 geocodergeokit-rails です。

まずこの2つのGemにフォーカスして話を進めていきます。

GeocoderとGeokit

これらのGemは住所から緯度経度を割り出したり、緯度経度を用いた検索ロジックを提供しております。

具体的には以下の様な事ができます。

  • 住所から緯度経度を割り出す
  • 緯度経度から住所を割り出す
  • IPアドレスから緯度経度を割り出す
  • 指定したオブジェクトまたは緯度経度を中心に、指定した距離内や範囲(ex: 2km~5km)にある施設を検索する
  • 2点間の距離を算出する
  • あるオブジェクトに対して指定したオブジェクトが位置する方角を示す
  • 指定したオブジェクトまたは緯度経度を中心に、長方形状に指定した範囲内ある検索する

住所から緯度経度を割り出すとは、「東京都中央区◯◯」という文字列を判別し、北緯35度、東経139度というように緯度経度に直すことです。

GeocoderとGeokitの比較

Geocoderの利点

Geocoderを使うメリットは、住所から緯度経度を割り出す機能が優秀という点です。

GeocoderはGeokitより多くのAPIを網羅しております。

GeokitはGoogle・Yahoo・Bing・FCC・MapQuest・Mapbox・OpenCageの7つに対して、 Geocoderは上のFCCを除いたものに加えて、Google Maps API for Work・Google Maps API for Work・Nominatim・Yandex・Geocoder.ca・Geocoder.us・Ovi/Nokia・Here/NokiaESRI・Mapzen・Pelias・Data Science Toolkit・Geocodio・SmartyStreets・OKF Geocoder・Geoportail.lu・PostcodeAnywhere Uk・LatLon.ioの25個網羅しています。

使用できるAPIの数が多いほうが、最適なものを選べるので使い勝手がいいですね。

Geokitの利点

一方、Geokitを使うメリットは、オブジェクトを絞るメソッドを使用する際メソッドチェーンが使えるという点です。

Geocoderだと可能な場合と不可能な場合があるようです。

例えば、Geokitのメソッドであるwithinを使うとき、

prefecure_id = 1
shop_type = restaurant
latitude = 33.33
longitude = 140.44

Shop.within(2, [latitude, longitude]).tap do |scoped|
  scoped.where!(prefecure_id: prefecure_id) if prefecure_id
  scoped.where!(shop_type: shop_type) if shop_type
end

のようなことが出来ます。 例えば絞込を行う等、メソッドチェーンを使用したい場面を想定するとGeokitのほうが使い勝手が良いですね。

上記の理由により今回は、

  • Geocoder: 緯度経度の割り出しを行う
  • Geokit: 現在地周辺検索を行う

の様な使い分けをしました。

ちなみにgeocodergeokitの人気を比較しているサイトがあったので載せておきます。

ruby.libhunt.com

Geocoderの使い方

住所から緯度経度を割り出すことを geocoding といいます。 geocoding を行いたいカラムがあるモデルに以下のように記述します。

geocoded_by :address
after_validation :geocode, if: :address_changed?

geocoded_bygeocoding を行いたいカラムを指定します。 addressというカラムに住所(ex: 東京都港区〇〇)が入っており、その住所を基に検索を行いたいような場面です。

after_validationgeocoding するタイミングを指定します。 上のように書くと、addressカラムに変更があった際に、自動でgeocodingされるようになります。

Geokitの使い方

緯度経度を使って出来ることを、GitHubより抜粋しました。

# 指定した緯度経度から半径5km内のオブジェクトを検索
Shop.within(5, origin: [33.33, 140.33]) 

# 指定した緯度経度から半径5km外のオブジェクトを検索
Shop.beyond(5, origin: [33.33, 140.33])  

# 指定した緯度経度から2km~5km内のオブジェクトを検索
Shop.in_range(2..5, origin: [33.33, 140.33]) 

# 緯度が30.33~35.55内でかつ、経度が135.55度~145.55度内にあるオブジェクトを検索
Shop.in_bound([[30.33, 135.55], [35.55, 145.55]]) 

# 指定した緯度経度から一番近いオブジェクトを検索
Shop.closest(origin: [33.33, 140.33])

様々な検索方法がありますね。 因みにGeocoderでも同じようなこと検索は可能です。

現在地の検索機能

では、現在地より半径2km以内にある店を検索する機能を実装していきます。 「現在地から探す」ボタンを押した時に、上記の条件で検索が行われるような実装です。

「現在地から探す」ボタン押下後の挙動としては、 Javascriptを用いて現在地の緯度経度情報を取得→Geokitのメソッドを用いて緯度経度付近にある施設を検索して、Viewに表示させる という流れになります。

Model

Shopモデルのaddressカラムをgeocodingします。

  • models/shop.rb
geocoded_by :address
after_validation :geocode, if: :address_changed?

address_changed?というメソッドはActiveRecord::Dirtyの機能です。{column_name}_changed?で該当するカラムが変更された時にtrue`を返します。 詳しくは下記を御覧ください。

qiita.com

Controller

Geokitのwithinメソッドを用いることにより、現在地から2km以内の店が@placesに渡されます。

  • shops_controller
def search
  latitude = params[:latitude]
  longitude = params[:longitude]

  @places = Shop.all.within(2, origin: [latitude, longitude])
end

View

  • shops/index
    「現在地から探す」ボタン部分になります。
.currentLocation
  = button_tag ‘現在地から探す’, type: ‘button’

Javascript

現在地の取得には、HTML5Geolocation APIを使用します。 以下の様なコードになります。

class @CurrentLocations
  @getCurrentLocation: ->
    $('.currentLocation').on 'click', ->
      if navigator.geolocation
        navigator.geolocation.getCurrentPosition(successGetPosition, failGetPosition, options)
      else
        message = 'ご使用中のブラウザは現在地検索に対応されておりません。'
        Alert.set('warning', message)

  successGetPosition = (position) ->
    window.location.href = "/shops/searches?latitude=#{position.coords.latitude}&longitude=#{position.coords.longitude}"

  options =
    enableHighAccuracy: true

  failGetPosition = (error) ->
    switch error.code
      when 1
        message = '位置情報の提供を許可してください。'
      when 2
        message = '位置情報の取得に失敗しました。'
    Alert.set('warning', message)

では上から見ていきます。

  @getCurrentLocation: ->
    $('.currentLocation').on 'click', ->
      if navigator.geolocation
        navigator.geolocation.getCurrentPosition(successGetPosition, failGetPosition, options)
      else
        message = 'ご使用中のブラウザは現在地検索に対応されておりません。'
        Alert.set('warning', message)

@getCurrentLocation が現在地を取得する関数です。

navigator はブラウザの情報を取得するオブジェクトです。 そして.geolocationでブラウザが Geolocation API に対応しているか調べています。 対応していないブラウザもあるので注意して下さい。(IE8.0など)

ブラウザが Geolocation API に対応している時、 geoCurrentPosition で現在地の取得を試みます。 geoCurrentPosition の第一引数は現在地の取得に成功した時に実行され、第二引数は失敗した時に実行されます。 第三引数は現在地の取得の際のオプション設定をしております。

ちなみにブラウザが Geolocation API に対応していてもユーザーが位置情報の提供を許可していない状況も考えられます。 そのような場合、 geoCurrentPosition が呼ばれると自動で許可するか否かのポップアップが出るようになっております。これまた便利ですね。

ブラウザが Geolocation API に未対応である場合は、 else の部分が実行されます。 ここでは「対応していません」というアラートを出すようにしています。

  successGetPosition = (position) ->
    window.location.href = "/places/searches?latitude=#{position.coords.latitude}&longitude=#{position.coords.longitude}"

successGetPosition は現在地の取得に成功した時の関数です。 positionオブジェクトに現在地の情報が入っており、position.coordsで様々な情報を取り出せます。

例えば、 position.coords.latitude で緯度を取得できたり、 position.coords.logitude で経度を取得できます。

そして現在地の取得に成功した時に、現在地周辺の店の一覧ページに移動します。 またControllerに緯度経度の値を渡しております。

  options =
    enableHighAccuracy: true

options はその名のとおり、現在地取得の際のオプション設定です。 enableHighAccuracyGPSなどを使った高精度な現在地の取得を可能にします。 他にもタイムアウト設定やキャッシュの設定なども可能です。

  failGetPosition = (error) ->
    switch error.code
      when 1
        message = '位置情報の提供を許可してください。'
      when 2
        message = '位置情報の取得に失敗しました。'
    Alert.set('warning', message)

failGetPosition は現在地の取得に失敗した時に実行される関数です。 error というオブジェクトに失敗の原因が入っております。 今回は、エラーの原因ごとに別々のアラートを出したいので、 error.code ごとに条件分岐をしております。

error.code = 1 はユーザーが位置情報の許可をしていない時を指しております。
error.code = 2 は現在地の取得に失敗した時を指しております。

Geolocation API の詳しい情報は以下のリンク先にも書かれているので参考にしてみてください。

HTML5 Geolocation

以上が現在地周辺の施設を検索する機能の解説でした。 非常に便利なGemですね。

改良点等アドバイスいただけたら大変幸いです。

参考

今のうちに見直しておきたいnginx設定集 【セキュリティ編】

こんにちは、Cluexの高橋です。

先日EC2サーバーのOSを新しいものにしまして、その時にサーバーのテストを簡単に行ってくれるQualys SSL Labsで移行前のサーバーをテストしてみたところ、C判定が出てしまったので、nginxの設定も全体的に見直してみました。

     

イメージはこんな感じです f:id:cluex-developers:20160813190017p:plain    

テストしたのはこちら「Qualys SSL Labs」 www.ssllabs.com    

ということで今回はnginxの設定に関してセキュリティ関連でやっておくべき設定集をまとめました。      

nginxのバージョン情報を隠す

nginxのバーション情報を隠蔽します。

server {
  # ~~
  server_tokens off;
  # ~~
}

   

SSL通信に使用するプロトコルを指定する

SSLv2やSSLv3はダウングレード攻撃やPOODLEなどへの脆弱性があるのでTLSのみ許可します。

server {
  # ~~
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  # ~~
}

   

暗号化スイートの設定

SSLの暗号化にする暗号化スイートを明示的に指定し、クライアントサイドで指定した暗号化をしないようにすることで、通信をよりセキュアにすることができます。 ちなみにssl_ciphersの設定方法としては、「:」をデリミタとして使用し、「!」をプレフィックスでつけることで除外対象となります。  

詳細な暗号化スイートの設定内容はこちらのサイトを参考にさせていただきました。

Strong SSL Security on nginx - Raymii.org    

おすすめの設定がこちら。

server {
  # ~~
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  # ~~
}

 

IE6/WinXP などにも対応したいと言う方にはこちらの設定がおすすめとのことですが、SSL3.0などを使用できない設定にしているので今回は特にIE6を気にする必要はないかと思います。

server {
  # ~~

  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

  # ~~
}

   

サーバーの暗号化設定の優先

先ほどのサーバー側で指定した暗号化スイートを優先して使用するようにします。

server {
  # ~~
  ssl_prefer_server_ciphers on;
  # ~~
}

   

Http Strinct Transport Security(HSTS)ヘッダの追加

サーバーからStrict Transport Securityヘッダを返すことで常にHTTPSで通信を行うようにし、中間者攻撃を防ぎます。これを使用するには Nginxのngx_http_headers_moduleが必要になります。

add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';

developer.mozilla.org

   

ちなみにpreloadオプションを使用したい場合は、こちらでドメインを登録しておくと宜しいかと思います。

HSTS Preload List Submission

こちらに登録するには下記の要件を満たす必要があります。

Submission Requirements

If a site sends the preload directive in an HSTS header, it is considered be requesting inclusion in the preload list and may be submitted via the form on this site.

In order to be accepted to the HSTS preload list through this form, your site must satisfy the following set of requirements:

  1. Serve a valid certificate.

  2. Redirect from HTTP to HTTPS on the same host.

  3. Serve all subdomains over HTTPS.

 ・In particular, you must support HTTPS for the www subdomain if a DNS record for that subdomain exists.

  1. Serve an HSTS header on the base domain for HTTPS requests:

 ・The max-age must be at least eighteen weeks (10886400 seconds).

 ・The includeSubDomains directive must be specified.

 ・The preload directive must be specified.

If you are serving an additional redirect from your HTTPS site, that redirect must still have the HSTS header (rather than the page it redirects to).      

preloadを指定する場合はこんな感じです。

add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;preload';

       

DH鍵交換時のKeyの強化

TLSプロトコルで採用されているDiffie-Hellman鍵交換は512bitもしくは1024bit以下のDHパラメータにおいてLogjam攻撃を受ける可能性があり、これを防ぐにはDHパラメータに2048bitのものを使用することが望ましいとされています。

   

Diffie-Hellman鍵交換による暗号化時にnginxのデフォルトでは1024ビットの鍵を使用しますが、Google ChromeMozilla Firefoxなどの主要なブラウザでは「最低でも」1024ビット以上のものを使用するよう推奨しており、できれば2048bitのものを独自生成して使用するのが好ましいかと思います。

  一般的なwebサイトでは2048bitもしくは4096bitでpemを作っておくといいようです。

   

まずはpemファイルの作成

$ cd /etc/ssl/certs
$ openssl dhparam -out dhparam.pem 4096

こちらがnginxのconfファイルに追加する内容。

server {
  # ~~
  ssl_dhparam /etc/ssl/certs/dhparam.pem;
  # ~~
}

     

OCSPステープリング(OCSP Stapling)の設定

OCSP(Online Certificate Status Protocol)はSSL/TLS通信の時に証明書が失効していないかを確認するために使用されています。 通常はSSL通信を行う際はクライアント側がこのOSCPを使用してサーバー証明書の正当性を確認する必要がありますが、サーバー側で事前にこの処理を行うことでクライアント側で行う必要がなくなるのでHTTPS通信の開始を高速化できます。

 

具体的にはOCSPステープリングによってクライアント側ではなくサーバー側でOCSPによるサーバー署名書の確認を行い、その結果をクライアントへのレスポンスと一緒に送るようにすることで、これを実現しています。

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/cert/trustchain.crt;
resolver 8.8.8.8 8.8.4.4 valid=300s

ssl_staplingを使用するにはDNSリゾルバを resolverディレクティブにて指定する必要があります。googleのパブリックDNSサーバーが使用されることが多いようです。    

X-Frame-Options

レスポンスヘッダにX-Frame-Optionsを設定することでブラウザがiframeなどの内部に自身のサイトを表示を許可するかを設定できます。DENYもしくはSAMEORIGINを指定することで自分のサイトのコンテンツが他のサイトに埋め込まれないように設定でき、クリックジャッキング攻撃を防ぐことができます。

add_header X-Frame-Options SAMEORIGIN;

 

X-XSS-Protection

XSSに対するフィルタ機能を有効化

add_header X-XSS-Protection "1; mode=block";

 

X-Content-Type-Options

Content-Typeに一致しない処理は行わないようにさせることでXSSなどを防ぎます。

add_header X-Content-Type-Options nosniff;

これが設定されていない場合、例えば Content-type="text/plain" のファイルでも、その中にjavascriptのソースがあるとブラウザによって実行される可能性があります。

     

再度テストした結果は・・・

f:id:cluex-developers:20160813185943p:plain    

当時の設定では上記の幾つかはまだ設定していないものもあるのでA+の評価をとることができなかったので、今回あげたものも含めてさらにサーバー周りを強化していきたいなと思います。

     

ちなみにMozilla Foundationが公開しているwebサーバーのConfig Generatorがあるので、そちらで基本的な設定を確認できるので、気になる方はお使いになってみるいいかと思います。

Generate Mozilla Security Recommended Web Server Configuration Files

       

余談)Cluexではエンジニアの方を探しています!

 

See more at cluex.co.jp

assets on S3の導入

こんにちは。エンジニアの志村です。 最近暑くて参りますね…。アイスばっかり食べてます。

さて今回ですが、Assets on S3を導入しましたのでその際のメモです。
結構この形でassetsを配信しているサービスは多いですよね。
今回は、Cloudfront+S3 / asset_sync+capistranoという定番のパターンで実装しております。

assets on S3とは

デプロイ時にassetsファイルをS3に配置し、CDN経由で配信する方法です。
通常であればnginxやApache等のWebサーバーを介して静的ファイルは配信されています。
assets on S3はassetsファイルをS3に配置し、CloudfrontやAkamai等のCDN経由で配信します。

Webサーバー負担軽減やCDNを噛ませることによる高速化を目的として用いられることが多いかと思います。

仕組み

下記のような流れになります。

  1. デプロイ時にrake assets:precompileを走らせる。その際にasset_syncを使用し、S3にassetsファイルをアップロードする。
  2. manifestファイルをEC2にアップロードする。
  3. rake assets:precompile時に作成されるassetファイルを削除する(public/assetsに格納されている)

こんな感じでしょうか。 他にもCloudfrontやS3の設定があるので、下記に記していきます。

Rails側の設定

ではまずasset_syncを導入し、bundle installをします。

asset_syncの導入

gem 'asset_sync'

次にasset_syncのconfigファイルを生成します。

$ rails g asset_sync:install --provider=AWS

今回はAWSを使用するのでproviderオプションにはAWSを設定します。 そうするとasset_sync.rbという設定ファイルが生成されます。

  • config/initializers/asset_sync.rb
AssetSync.configure do |config|
  # fogを使用するサービス
  config.fog_provider = 'AWS'
  # S3の存在するリージョン
  config.fog_region = 'ap-northeast-1'
  # S3のバケット名
  config.fog_directory = 'assets'
  # IAMのアクセスキー
  config.aws_access_key_id = 'xxxx'
  # IAMのシークレットアクセスキー
  config.aws_secret_access_key = 'xxxx'
  # 既にS3上に存在しているファイルの扱い keep, delete, ignoreから選択
  config.existing_remote_files = 'keep'
  # gzip圧縮をするかどうか
  config.gzip_compression = true
end if defined?(AssetSync)

上記で使用してるIAMに関しては、次の章のS3の部分で説明します。 これでasset_sync自体の設定は完了しました!

assetsのURLをCloudfrontにする

assetsファイルはCloudfrontより配信されます。 通常の設定では、http://domain/assets/配下のファイルが配信されますが、これをhttps://Cloudfrontのエンドポイント/assetsに変更し、Cloudfrontから配信するように設定します。

  • config/environments/production.rb
〜中略〜

  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
  config.action_controller.asset_host = '//xxxxx.cloudfront.net'

〜中略〜

これでassetsファイルがCloudfrontより配信されるようになりました!

次はcapistranoの設定を行います

capistranoの設定

流れとして、

  1. cap 〜 deployコマンドを叩いた時に、ローカルにてrake assets:precompileを走らせる(asset_syncが自動的にS3にアップロードしてくれる)
  2. manifestファイルをサーバのpublic/assetsディレクトリに転送する
  3. ローカルで生成されたpublic/assetsディレクトリを消去する

この中で特に大切なのは2.かと思います。
railsは、productionにデプロイされる際にprecompileを行います。
その際にdigestを付与してファイル名-digest.scssのようなファイル名に変更します。
このdigestはprecompile時にランダムに設定されるのでrails側で管理が必要になります。
そのファイル名を管理するのがmanifestファイルです。これが存在しないと、railsはassetのパスを正しく指定出来ません。

ではcapistranoの設定に移っていきます。 こちらのコードを参考にさせて頂きました。

qiita.com

  • config/deploy.rb
〜中略〜

namespace :deploy do
  # rake db:assets:precompileを実行する
  task :asset_sync do
    run_locally do
      Bundler.with_clean_env do
        execute :rake, 'assets:precompile'
      end
    end
  end

  # manifestファイルをアップロードする
  task :upload_manifest do
    on roles(:app) do |host|
      if test "[ ! -d #{release_path}/public/assets ]"
        execute "mkdir -p #{release_path}/public/assets"
      end
      file_path = Dir::glob('public/assets/.sprockets-manifest*').first
      upload!(file_path, "#{release_path}/public/assets")
    end
  end

  # ローカルに残されたprecompile後のassetsファイルを削除する
  task :assets_cleanup do
    run_locally do
      Bundler.with_clean_env do
        execute :rake, 'assets:clobber'
      end
    end
  end

  task :restart do
    invoke 'unicorn:restart'
  end
end

before 'deploy:starting', 'deploy:asset_sync'
after 'deploy:publishing', 'deploy:upload_manifest'
after 'deploy:publishing', 'deploy:assets_cleanup'
after 'deploy:publishing', 'deploy:restart'

〜中略〜

上記のようになります。
rakeタスクに関しては新しくファイルに切り分けても良いかと思いますが、そんなにデプロイスクリプトが多いわけでも無かったので僕はそのままdeploy.rbに書いてしまっています。
release_pathの部分はそれぞれの環境に合わせたpathを指定すればOKです。
developmentではsprocketsを使用しているのでそれをそのままuploadしております。

AWS側の設定

S3の設定

S3はバケットを作成し、CORSの設定を行います。 CORSの設定をしないと、Font Awesomeが正しく表示されません。 詳しくは

dev.classmethod.jp

を御覧ください。

  1. AWSコンソールの「S3」を選択

  2. 「バケットの作成」を選択

  3. バケット名、リージョンを設定

  4. 作成したバケットを選択し、「プロパティ」→「アクセス許可」→「CORS設定の編集」を選択 f:id:cluex-developers:20160810172755p:plain

  5. ここに下記のコードを貼り付け、「保存」をします 下記のコードを使用させて頂きました。

sora33.hatenadiary.com

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Cloudfrontの設定

基本設定

assets用のディストリビューションを作成します。

  1. AWSコンソールの「Cloudfront」を選択

  2. 「Web」を選択 f:id:cluex-developers:20160810152149p:plain

  3. Origin Settingsを入力する

項目 設定 説明
Origin Domain Name 先ほど作成したS3バケット名 オブジェクトの取得先
Origin Path 空のまま S3のルートディレクトリの設定
Origin-ID 分かりやすい名前 オリジンを区別する一意のID
Restrict Bucket Access Yes CloudfrontのURLからのみS3のオブジェクトにアクセス出来る
Comment 分かりやすい名前 identityを区別するIDのようなもの
Grant Read Permissions on Bucket Yes バケット内のオブジェクトの読み取り許可
Origin Custom Headers 空のまま リクエストをオリジンに転送する際にカスタムヘッダーを含めるかどうか

f:id:cluex-developers:20160810152400p:plain

※ Default Cache Behavior Settings, Distribution Settingsに関しては環境に応じて入力して下さい。今回は特にいじらずに行きます。

「Create Distributions」を選択するとCloudfrontのDistributionが作成されます。

Behaviorの設定

さて、Behaviorの設定を行っていきましょう。 Behaviorは振り分けのルールです。
例えば、

  • https://xxxx.cloudfront.net/assetsにリクエストが来た場合にはassetsバケットに転送
  • https://xxxx.cloudfront.net/imagesにリクエストが来た場合にはimagesバケットに転送

のようなことが可能になります。

  1. 「Behavior」タブの「Create Behavior」を選択 f:id:cluex-developers:20160810155354p:plain

  2. Settingsを入力

項目 設定 説明
Path Pattern /assets/* 振り分けパターン。今回は/assets配下のオブジェクト全てをS3から配信したいので/assets/*とする
Origin 先ほど設定したOrigin-ID どのオリジンからオブジェクトを取得するかを選択
Viewer Protocol Policy 環境によって選択 アクセスする際のプロトコルの選択
Allowed HTTP Methods GET, HEAD オリジンに転送するHTTPメソッド。今回は取得のみなのでGET, HEADを選択
Forward Headers Whitelist -> Origin どのヘッダを転送するか 今回CORSの設定を行っているので、OriginをAddする
Grant Read Permissions on Bucket Yes バケット内のオブジェクトの読み取り許可
Object Caching Use Origin Cache Headers MaximumTTL等を変更しないのであればUse Origin Cache Headersのままで良い

f:id:cluex-developers:20160810173203p:plain

「Create」を選択すると、このBehaviorが有効になります。

設定の反映までは10分〜20分ぐらいかかるので気長に待ちましょう!

以上です。 asset_syncのおかげでそこまで多くの手順を踏むこと無く、assets on S3の導入が出来ました。 次回はLambdaを使用してInvalidationを走らせる処理について書きたいと思います。

インターン生の村田です!

はじめまして、慶應義塾大学2(3)年の村田正之です。

2016年4月から株式会社Cluexでエンジニアとしてインターンをしております。 よろしくお願いします。あと、上のカッコはあまり気にしないでください。

株式会社Cluexで働く前

Cluexにジョインするまでは所属していた学生団体の活動に多くの時間を割いていました。大学と深い関係もありその歴史は10年以上という、学生団体としては比較的しっかりとした方だったと思います。そこではビジネスコンテストの運営、もう少し堅い言葉を使ってしまうとインキュベーション活動をしておりまして、最終的にはその代の副代表も務めておりました。

当時はあまり意識していなかったですが、その学生団体では本当にたくさんのことを勉強させていただきました。 リーンスタートアップやデザイン思考といったアイデアやビジネスの創造においての基本的な概念を学ぶことができましたし、僅かではありますが、マネジメントや組織の形成の仕方、ファシリテーションと言った汎用的な能力も身につけることができました。 ファシリテーションなどの能力はエンジニアと無縁に見えることもあるかもしれませんが、チームで開発をしていく上では非常に大切な能力の一つであり、現在でも活かされている場面が多いと思います。 そのようなことを学ばせていただけたという意味で、現在でもその学生団体には感謝を忘れることはできません。 しかし活動期間がありましたので、活動終了後は特別に打ち込むものもなく普通の学生生活を送っていました。

株式会社Cluexのインターンに応募したきっかけ

その学生団体のビジネスコンテストを運営していく中で、ものづくりができる人の強さを目の当たりにしてきました。 特に能力の高いエンジニアを抱えているチームはアイデアにとどまらず素早く行動に移すことができるため、短期間でピボットを繰り返していることがとても衝撃的でした。 

実はそのあたりから密かに、「エンジニアってかっこいいなあ」という憧れを抱き始めました。

そこで密かにプログラミングの本を購入して独学で勉強を始めました。 ただ、自分はエンジニアのコミュニティに属していなかったので、チャレンジしても誰にも相談できないまま解決できないということが何度か続き、結局挫折してしまいました。 そうしている中で、「もしプログラミングを学ぶなら優秀なエンジニアがいてスピード感のある環境に身を置きたい」と思いインターンを探していたところCluexというスタートアップを発見して応募しました。

当時は初心者でも受け入れてくれたので面接の応募をしたのですが、面接に行った際にサービスとプログラミングが大好きな人たちが働いている様子を見て、「ここでエンジニアとして働きたい!!」と感化されてしまいました。

いまやっていることと将来やりたいこと

Cluexでは2つのチームに分かれて開発を進めております。 1つがWebAppTeam、もう1つがNativeAppTeam(iOS)です。 私は前者のWebAppTeamでRubyonRailsを使って開発を進めています。 インフラ周りはまだほとんど触っていませんが、フロントエンドとバックエンドについてガリガリ書いています。

休みの日は業務以外のプログラミングを楽しんでいます。 最近はRubyメタプログラミングを勉強してるので、今週の日曜日は有名なgemの中身を読んでみようと思ってます。

今後はもっとミドルウェア周りを色々遊んでみたり、サーバーもいじっていきたいです。 あとハードにも興味があるので将来的にはソフトだけではなくて、ハード側も勉強したいと思っています。 ただ今から他の言語に浮気してもうまくいきそうにはないので、まずは我慢してじっくりRubyRailsに慣れていこうと思います。

Cluexではエンジニアの方を募集しています!

エンジニアリングと同時にビジネスマンとして成長したい、スタートアップで働いてみたい、もうレガシーな環境で余計な苦労しをたくないといった方など、 興味がある方はご連絡下さい。 https://www.wantedly.com/projects/60136

規律あるcssを運営するにあたって

こんにちは、エンジニアの井戸田です。

弊社ではmamanokoという子育てママさんのための情報サイトを運営しており、Ruby on Railsで実装しています。 今回はmamanokoで実装されているのcssの構成についてお話ししたいと思います。 mamanokoではSMACSSというcssの設計手法や、BEMというフロントエンド設計手法を弊社なりにカスタマイズして使用しています。

フロント面の開発環境は下記のようになっております。

SCSS
Slim
CoffeeScript

まずは本来のSMACSS、BEMについて説明します。

SMACSS

SMACSSとは、 Scalable and Modular Architecture CSS の略で スマックス と読みます。CSSの設計手法で1つであり、 Base(ベース)Layout(レイアウト)Module(モジュール)State(ステート)Theme(テーマ) の5つのルールに分け、それぞれのルールや記述規約が決められているのが特徴です。

smacssで設計する目的

SMACSSを導入することによって、コードの量が減り、CSSの弱点であった下記のことが解決されます。

  • 保守性を高める
  • メンテナンス性を高める
  • デザインを統一することで、ユーザー体験の一貫性を高める

5つのルール

Base - ベースルール

要素そのもののスタイルを定義します。 セレクタを使ってスタイルを変更する場所であるので、idやclassは使用できません。

body {
  background-color: #fff;
  color: #000;
}

a {
  &:hover {
    color: inherit;
  }
}

Layout - レイアウトルール

ページのエリア分けを定義します。 header , footer などよく id 指定するユニークな要素がLayoutに該当すると思います。 Modulestate との区別のため l- というprefixをつけるのが特徴です。このようにすることで、他のルールと区別ができ、管理がしやすくなります。

.l-header {
  height: 48px;
  background-color: #fff;
}

.l-footer {
  background-color: #fff;
  border-top: 1px solid #000;
}

Module - モジュールルール

その名前の通り再利用可能なスタイルを定義します。 ページデザインのcssを書くにあたって、ほとんどがここに定義されると思います。 どこにおいても再利用できるように独立させておきます。

またクラスの書き方は モジュール名-サブクラス の順番で書きます。

.article
  p.article-title タイトル
. article {
  background-color: #fff;
  border: 1px solid #000;

  &-title {
    color: #000;
  }
}

State - ステートルール

状態によってデザインを上書きする時に定義します。 !important を使用してのデザインの変更は避けましょう。 !important を使用することで醜いコードになってしまいます。 ステートルールはモジュール名を付けてあげると、クラス名で被ることはないと思います。

.is-item-active
.is-item-hidden

Theme - テーマルール

テーマルールを使用する機会は少ないです。 他言語対応時、英語や中国語など言語で標準のフォントサイズでは小さい場合があるので、そのような場合にテーマルールを使用することもあります。 theme- というprefixをつけるのが特徴です。

BEM

BEMとは Block , Element , Modifier の頭文字を取ったもので、 ベム と読みます。 コンポーネント化のためのclss命名規則です。

BEMで設計する目的

BEMを導入することによって、パーツごとにclass名を完全に独立したものとできるので、下記のことが解決されます。

  • 再利用性を高める
  • 拡張性を高める
  • 開発の生産性とメンテナンス性を高める

BEMの規約

  • Block
    • 文字通りブロック(塊)。構成のルートとなる要素です。
  • Element
    • Blockに所属する子要素。必ずBlockの中でのみ存在し、単体では使用してはいけません。
  • Modifier
    • 元となるBlock又はElementから変化した状態を示すものです。

上記の元に下記の規約が定められています。

  • BlockやElementで2つ以上の単語の場合はハイフン1つ(-)
  • Modifierで2つ以上の単語の場合はアンダースコア1つ(_)
  • BockとElementはアンダースコアを2個(__)
  • Block又はElementとModifierはハイフンを2個(--)
.articles-list
  .articles-list__item
    .artiles-list__item__title
      | タイトル

  .articles-list__item--state_small
    ・
    ・
    ・

弊社のSMACSSとBEMの構成

まず弊社ではマルチクラス設計を採用しています。 マルチクラス設計とは、HTMLに複数のclassを書いて、スタイルを当てる設計のことです。 マルチクラスを採用することにより、冗長な記述が減り、保守性の向上につながります。

例) ピンクのボタン(.button-pink)と、緑(.button-green)のボタンを定義

/ good

.button {
  padding: 12px 20px;
  background-color: #fd8280;
  border: 1px solid #fd6360;
  border-radius: 2px;
  color: #fff;
  
  &-pink {
    background-color: #fd8280;
    border: 1px solid #fd6360;
  }
  
  &-green {
    background-color: #3de933;
    border: 1px solid #0ce400;
  }
}

/ bad
.button { 
  &-pink {
    padding: 12px 20px;
    background-color: #fd8280;
    border: 1px solid #fd6360;
    border-radius: 2px;
    color: #fff;
  }
  
  &-green {
    padding: 12px 20px;
    background-color: #3de933;
    border: 1px solid #0ce400;
    border-radius: 2px;
    color: #fff;
  }
}

SMACSS

本来では5つのルールに分けるのですが、弊社では7つのルールに分けて使用しています。
smacssでは、ほとんどのスタイルが module に定義されると思うのですが、 module をもっと細かいルールに分けることによって、fatになってしまいがちの module を防いでいます。

  • Base
    本来のSMACSSと同じで、要素そのもののスタイルを定義します。
    セレクタを使ってスタイルを変更する場所であるので、idやclassは使用できません。
a {
  color: #000;
}
  • Component
    component に書くものなのですが、 見出し 部分や ボタン など、どこのページでも使い回す要素をここで定義します。そのため、グローバルなクラス名を付ける必要があります。
    現在のmamanokoでは見出し部分のクラス名は .heading 、ボタン部分のクラス名は .button と付けています。
.heading {
  border-bottom: 1px solid #000;
  padding: 0 8px;
  margin: 0 0 10px
}
  • Module
    moduleも使い回す要素を定義します。componentとの違いとして、グローバルなclass名をつけない要素を定義するということです。主にグローバルなクラス名ではない要素のほどんどが、ここに定義されます。

ユーザページのアバター画像及び、ユーザーネームを表示するヘッダーのcssを作成する場合

.userHeader {
  padding: 20px;
  background-color: #fff;
  
  &_image {
    width: 80px;
    height: 80px;
  }
  
  &_name {
    font-size: 80%;
  }
}
  • Layout
    本来のSMACSSと同じで、header , footer などよく id 指定するユニークな要素のものを記述し、 l- というprefixを付けて他のルールと区別するようにしています。

  • Patch
    使い回しをしない、特定のcssを定義するルールです。現在ではcontroller名ごとにファイルを分けをしており、ファイル内ではactionごとにcssを変更するようにしています。このようにすることによって、特定のページだけcssが変更することができるのを加えて、componentやmoduleのcssを打ち消すことができます。 但し patchを使いすぎると、醜いコードになってしまうので注意が必要です。

.users_controller {
  .edit_action {
    .heading {
      font-size: 80%;
    }
  }
}
  • Lib
    mixinなどの関数や、colorコードを変数で定義するルールです。
    mixinなどの関数を1ファイルにまとめておくことで、保守性を高め、メンテナンスがしやすくなると思います。 またcolorコードを変数で定義することにより、他のルールでcolorコードを設定する場合に、定義した変数を使うので、保守性、メンテナンス性を高めるのはもちろん、ユーザー体験の一貫性を高める効果があると思います。

現在mamanokoではここに定義されたcolorコードの変数を使い、色を濃くするにはscssの関数である darken や、色を薄くするには独自に関数を作成したものを使用しています。

@mixin rounded-s {
  border-radius: 2px;
}

@mixin rounded-m {
  border-radius: 4px;
}
$base-color: #000;
$primary-color: #ff828c;
  • Vendor
    外部ライブラリのcssを書き換えるルールです。現在mamanokoではBootstrapを使用しているのですが、デフォルトでcssが定義されており、うちのサイトにあったデザインにするためcssを書き換えています。

BEM

本来のBEMでは上記でも書いたようなルールがあります。

- BlockやElementで2つ以上の単語の場合はハイフン1つ(-)
- Modifierで2つ以上の単語の場合はアンダースコア1つ(_)
- BockとElementはアンダースコアを2個(__)
- Block又はElementとModifierはハイフンを2個(--)

BEMの本来の形のまま実行してしまうと、下記のようなデメリットがあります。

  • クラス名が冗長になってしまうので、コーディング量が増える
  • 深くネストした要素はクラス名が複雑になってしまう

このデメリットを防ぐために、弊社では独自のルールを制定しています。

弊社のルール

  • BlockとElement又はModiferとElementの区切りはアンダースコアを1つ( _ )
/ good
.block_element
.block-modifier_element

/ bad
.block__element
.block--modifier__element
  • BlockとModifier又はElementとModifierの区切りはハイフンを1つ( _ )
/ good
.block-modifier
.block_element-modifier

/ bad
.block--modifier
.block__element--modifier
  • BlockやElement, Modifierが2つ以上の単語で表す場合キャメルケースを使用する
/ good
.articlesList
  .articlesList_container

/ bad
.articles-list
  .articles-list__container
  • ElementのElementは記述しなくて良い
/ good
.articlesList
  .articlesList_container
    .articlesList_title
    
/ bad
.articlesList
  .articlesList_container
    .articlesList_container_title

いかがでしょうか? SMACSSのルールをより細分化、BEMを冗長性を防ぐためハイフンや、アンダースコアを省略することで、より使いやすくなると思います。 最初は慣れないと思いますが、慣れてこれば簡単に要素のcssを検索することができるのではないでしょうか。

最後まで読んでいただきありがとうございました。

はじめまして、エンジニアの神山です!!

はじめまして、神山奎吾です。2016年4月から株式会社Cluexでエンジニアとして働いております。よろしくお願いします。

株式会社Cluexで働く前

2016年4月に私は新卒としてCluexにジョインしたのですが、それまでは別の会社で営業をしておりました。そこは大学4年次の4月に内定を頂いたところで、それから大学生ながらも働かせて頂きました。会社規模はCluexとほとんど変わらないスタートアップ企業でした。なぜ営業を選んだのかというと、当時からエンジニアに興味を持っていたのですが、「知識・経験がゼロの状態から始めるのなら営業でいいや」という安易な考えでした。またエンジニアを志した理由もただ興味があるだけで、そもそも将来にやりたいことすら曖昧でした。自分でやりたいと思った事業を創ること、また自分で引っ張る、時に起業できるぐらいの実力者になれたらいいなといった感じでした。

入社して最初の1,2か月はテレアポで新規クライアントの開拓をしてました。毎日200件近く電話をしておりました。しかも最初の2週間くらいはまったくアポが取れずすべて断られ続け、精神的にとても辛く苦しい思いをしました。あまりにもできなかったのが悔しく、休みを利用してテレアポの派遣に登録しテレアポのプロたちの会話術を必死に聞いて真似しておりました。そしてようやくその次の日からアポが取れるようになりました。アポが取れた時に同僚の方々に拍手喝采して頂き、このときの嬉しさは今でも忘れることが出来ません。 今振り返るとこのとき逃げずに挑戦し続けた経験が自分を精神的にかなり強くしてくれたと思います。またダメだった状態から50件に1件ぐらいの割合でアポがとれるようになると仕事がとても好きになり、強い自信を持つことができました。

テレアポの次は実際に広告を運用しており、当月の売り上げを先月の1.25倍にするというノルマのもと働いておりました。この仕事で毎月に一定額以上の利益を出す大変さを学ぶとともに、有限な時間をいかに有効的に使うかを意識して働いておりました。この仕事もハードでしたが、なんとかノルマを達成し続けることができました。このときに努力と根性と少しのクレバーさがあれば人間何でもできると気づきました。

株式会社Cluexに入社したきっかけ

入社して半年ぐらいしたときに、自分は将来何がしたいのか、どのような働き方をしたいのか考えるようになりました。そもそもなぜスタートアップ企業で働いているのかというと、爆速で実力をつけられる一番の環境だったからであり、なぜ実力を付けたいのかというと、実力があれば仕事に困ることもないどころか多種多様な仕事を良い条件でできる、本当の意味での安定が手に入る、また自分の好きな仕事を好きなようにできる、時に旅に出たりなど自由気ままに生きていけると考えていたからでした。 またなぜエンジニアに興味を持ったのかというと、昔から自分はものづくりが好きであり、仕事を楽しみたいとしたらエンジニアが一番なのかなと思ったことでした。欲を言えば自分の代名詞となる世界的なサービスを作りたいと思っておりました。またパソコンやインターネットに興味があり、FacebookAppleに憧れておりました。理想は自分が0の状態からコードを書いたものを、事業として大きくスケールアップさせ、そのサービスが語られるときに自分の名前もセットで語られることです。

そして当時働いていた会社が上場を考えており、もし本当に究極のなりたい自分になるのなら、今エンジニアを目指すべきだと考え、会社をやめることにしました。社会人の基礎や営業のやり方を学ばせて頂き、公私共に大変お世話になっていたので、自己都合で辞めたことは大変申し訳なく感じております。

その後、2月の終盤ごろにCluexに声をかけて頂きました。最初は社歴がとても短く人数もごく少数の会社なので、未経験のエンジニアとして採用されたとして自分の希望通りに働けるのか、未経験を育てるだけの余裕や教育方針があるのか、悪い意味での何でも屋になるのではないかという不安もありました。しかし話を聞いてみると、エンジニアのリーダーが私と同じく営業上がりで未経験ながらもエンジニアに転職した方であったり、そもそもエンジニアとして経験が豊富な方がいらっしゃったりして、当初の不安は感じませんでした。また人と人の距離がとても近く団結力があり、しかも全員がやる気に満ちており凄く魅力的な会社だなと思いました。 それから何回かCluexに足を運んでいたのですが、メンバー全員が毎日朝から晩まで働いていて、しかもそれを当たり前のように笑って仕事をしているという環境がとても羨ましく、自分もここで働きたい、ここなら爆速で実力を付けられると思い、Cluexで働きたいと強く思うようになりました。また社員の皆さんにも歓迎していただけまして、3月中旬にジョインが決まりました。

いまやっていることと将来やりたいこと

現在、Ruby on Railsにて開発しております。4月1日にRoRチュートリアルを始めたので3ヶ月と少し経ちます。当時は何もかもがわからない状態でした。プログラミング自体が初めてで、ターミナルって何?どうやって動いているの?みたいな状態でした。 入社してからはいままで休むことなくパソコンのキーを叩いております。というのも寝てる時間以外常に仕事のことを考えております。仕事が楽しくて楽しくて仕方がない状態です。現在入社して3ヶ月目ですが、出来ることが格段に広がりました(勿論、知識が足りてないところは大いにありますが…)。最近はReactをガシガシ書いており、Reactを書いている時間が日々の楽しみになっております。 また、最近はWebアプリケーションチームとして、少人数のチームが構成され、チームを意識した働き方をしております。この会社に入って個々人で開発していた日々から、本格的にチームとして動くようになり、この先、皆で何かを成し遂げたいと思うようになりました。また会社的にもまず上場をさせるという目標があるので、その時が楽しみでなりません。その場面に立ち会ったときには、自分も会社の重要な軸になっているようにより一層の努力を重ねるつもりです。

将来的には、全世界の人々に楽しんで頂けるようなサービスを作りたいと考えています。年齢や性別、言語や文化関係なく、その時一瞬でも幸せを感じて頂けるサービスを作りたいと考えております。自分は大学時代ずっとマジックをやっており、その時にマジックは全世界の人に平等に驚き、またちょっとした幸せを与えられることを知りました。それをITサービスにできたら、上記の目標に一歩近づけるかなと思います。 私の好きな言葉に、「無駄とユーモアが人を幸せにする」という言葉があります。例えば、カロリーが高いけど、美味しいケーキを食べたとき、またしょうもないジョークにも関わらず、なんか疲れが吹き飛んだ時とか、一見あまり価値のなさそうなことに人は幸せを感じ、それらが積み重なってその人の大きな幸せになっていくのだと強く感じます。もし自分が世界の人々を少しでも幸せにできたら、それだけで自分の生きた意味になるのかなと思います。

Cluexではエンジニアの方を募集しています!

エンジニアリングと同時にビジネスマンとして成長したい、スタートアップで働いてみたい、もうレガシーな環境で余計な苦労しをたくないといった方など、 興味がある方はご連絡下さい。 https://www.wantedly.com/projects/60136