Published on

styled-componentsで別のコンポーネントがhoverされたときにスタイルを当てる

Authors

styled-components を使って開発を進めていくと、別のコンポーネントが hover されたときに背景色やテキストカラーを変更したい!ってことがあったので今回はその実装方法について説明していきたいと思います。

注意: ちなみにこの方法は Web 固有みたいで react native だと動かないらしいです。(公式参照)

親が hover されたときに子のスタイルを変更する

div(Wrapper)の中に a タグ(Link)があることを想定してみます。

親が hover された時に子のスタイルを変更したい場合には、子の要素内で親のコンポーネントを呼び出してあげれば変更することができます。

dev_tool_screenshot_parent_to_child.png

実際に Chrome の DevTool で見てみると hover した際に div のクラス名が紐付いて Link のスタイルを変更しているのがわかります。

親から子でスタイルを変える場合も方法は同じなので場面によって使い分けてください!
ただし使い分ける際にはコンポーネントの定義する順番に注意する必要があります。

// Wrapperが定義されていないのでエラーが出る
const Link = styled.a`
  ${Wrapper}:hover & {
    color: white;
  }
`

const Wrapper = styled.div`
  width: 300px;
  height: 100px;
  background: #f00;
`

上記のように Link で Wrapper を呼び出しているにも関わらず Wrapper を先に定義していない場合にはエラーが出てしまうため、呼び出す際には順番も意識して実装してみてください。

同階層のコンポーネントが hover されたときに

次に同階層の要素に対してスタイルを当てる場合です。
同階層に対してスタイルを当てる場合には css の隣接兄弟結合子(adjacent sibling combinator)を使っていきます。

直前の要素 + 対象の要素 { スタイルプロパティ }

これは要素が同階層の場合でも+を使うことで直前の要素に対して対象の要素のスタイルを変更できるものです。

実際の例です。

const BlockA = styled.div`
  width: 300px;
  height: 100px;
  background: #f00;
  display: inline-block;
`

const BlockB = styled.div`
  width: 300px;
  height: 100px;
  background: #00f;
  display: inline-block;
`

const Wrapper = styled.div`
  & ${BlockA}:hover + ${BlockB} {
    background: #0f0;
  }
`

// Component
<Wrapper>
  <BlockA />
  <BlockB />
</Wrapper>

上記の例は BlockA が hover された際に BlockB の背景を緑色に変更しています。
同階層の要素に対してスタイルを指定する場合には親要素で定義をしてあげる必要があるので注意してください。

これで BlockA が hover された時に BlockB を緑色に変更することができました。

まとめ

styled-components をかれこれ 1 年ぐらい書き続けているのでこういった Tips 系の記事を今後も書いていければと思います。