Несколько дней назад мой друг попросил помочь с решением задачи, которая была на его собеседовании. Интервьюер дал ему следующий фрагмент кода:


tbody:hover tr {
  opacity: 0.24;
}

Также добавил: “Сейчас, при наведении на таблицу, все строки становятся блеклыми. А требуется сделать так, чтобы строка, на которую навели, оставалась активной”.




Решение


В текущем решении при наведении на элемент tbody:hover сразу все элементы tr меняют свою непрозрачность на 0.24.


tbody:hover tr {
  opacity: 0.24;
}

Мне же нужно изменить селектор так, чтобы непрозрачность применялась ко всем элементам tr кроме того, на который навели.


Для такой реализации потребуется использовать псевдоклассы hover и not. С помощью hover браузер определит, что на строку навели, а при помощи not он поймет, что к ней не надо применять стили.


tbody:hover tr:not(:hover) {
  opacity: 0.24;
}

Домашняя задача


Для закрепления я подготовил домашнюю задачу, в которой требуется исправить ошибку при выводе изображения в тексте. Я подготовил следующую разметку и стили:


<main class="content">
  <p>Some text</p>
  <img src="picture.jpg" alt="some alt">
  <p>Some text</p>
</main>

.content img {
  margin-top: 35px;
  margin-bottom: 35px;
}

Ошибка заключается в том, что если изображение будет первым элементом, у него по прежнему остается отступ сверху, а нужно сделать так, чтобы его не было.


<main class="content">
  <img src="picture.jpg" alt="some alt">
  <p>Some text</p>
  <p>Some text</p>
</main>

Соответственно, если изображение является последнем элементом, то требуется убрать отступ снизу.


<main class="content">
  <p>Some text</p>
  <p>Some text</p>
  <img src="picture.jpg" alt="some alt">
</main>

Комментарии (23)


  1. andreymal
    28.05.2019 10:03

    Строки — это фигня детсадовская, вот бы столбец выделить как-нибудь


    1. Spaceoddity
      28.05.2019 10:19

      Ну с псевдоэлементами можно поиграться:
      css-tricks.com/simple-css-row-column-highlighting


      1. zag2art
        28.05.2019 11:39

        А есть ли решения без

        overflow: hidden;
        
        и хаков типа
          top: -5000px;
          height: 10000px;
        
        ?


        1. Spaceoddity
          29.05.2019 16:29

          Да, «display:grid» называются)


    1. Keyten
      28.05.2019 15:55

      Ну помимо какого-нибудь селектора типа contains… На css grid можно превратить строки в столбцы наверняка.


  1. Spaceoddity
    28.05.2019 10:13

    Это что за «задачи» такие?))

    .content img:first-child{
      margin-top:0;
    }
    .content img:last-child{
      margin-bottom:0;
    }


    1. Kesha_kh
      28.05.2019 10:37

      С тем что сейчас встречаются «фронтенд» разрабы не умеющие верстать, не удивительно появление таких задачек
      p.s. Можно вообще без псевдоклассов

      .content img + p ,
      .content p + img {
      margin-top: 35px;
      }


      1. WanSpi
        28.05.2019 13:41
        +1

        И все же лучше с псевдоклассами, так как Ваш пример не будет коректно работать, к примеру:

        <main class="content">
          <p>Some text</p>
          <img src="picture.jpg" alt="some alt">
          <div>Some text</div>
        </main>
        


        1. Kesha_kh
          28.05.2019 13:59

          или поменять селектор на:

          .content img + * ,
          .content * + img 


          1. WanSpi
            28.05.2019 14:05

            Такой подход тоже имеет недостатки перед псевдоклассом, так как что если один из наших элементов, который стоит после изображения, должен иметь отступ сверху больше 35 пикселей? Из-за чего нужно помнить ставить приоритеты, или импортанты, лишняя память которую нужно держать в голове :)
            Ну и к тому же лучше не забывать «хорошую» производительность селектора "*".


    1. melnik909 Автор
      28.05.2019 17:05

      Можно с использованием not написать так, что не потребуется сбрасывать отступы


  1. tsukasa_mixer
    28.05.2019 13:38
    +2

    какие-то извращения c :not.
    Пишем проще и не ломаем людям голову


    table:hover tr {
        opacity: .24;
    }
    
    table:hover tr:hover {
        opacity: 1;
    }


    1. melnik909 Автор
      28.05.2019 17:13
      -1

      В вашем способе создаются 3 правила: для основной стилизации tr, для стилизации tr при наведении на таблицу, стилизация tr при наведении на таблицу и строку. В моем 2 правила: основная стилизация вместе с opacity: 0.24 и стилизация при наведении на таблицу и строку.


    1. MiXei4
      29.05.2019 08:09

      Одно правило всегда лучше двух.
      Просто представьте, что нам нужно менять не только прозрачность но и цвет текста, и фон и ещё что-то. Правила начинают расти, дублироваться. А потом поменяв в одном месте, забудем поменять в другом, что частично решается препроцессорами или переменными, но это и называется извращения, когда можно обойтись простым правилом — «примени это ко всем строкам таблицы под курсором, кроме собственно той под которой курсор».

      Так же :not очень полезен для более частых случаев типа «примени ко всем строкам, кроме первой» и тп.


  1. Manyaka
    29.05.2019 20:50
    +1

    .content img:not(:first-child) {
      margin-top: 35px;
    }
    
    .content img:not(:last-child) {
      margin-bottom: 35px;
    }
    

    Мне еще нравится через :not убирать margin-bottom в списках или у параграфов:

    ul li:not(:last-child) {
      margin-bottom: 1em;
    }
    


    1. melnik909 Автор
      29.05.2019 20:55

      Manyaka, для списков, параграфов я тоже использую. А вот ваш пример кода я бы переписал так:

      ul li:nth-child(n+2) {
        margin-top: 1em;
      }
      


      Селектор проще в моем случае. Как думаете? Еще, если интересно, могу прислать в личные сообщения пару ссылку на мой инстаграм профайл, где я делюсь советами.


      1. Manyaka
        29.05.2019 22:08

        Я думаю, что, что такое «n+2» надо ещё посчитать, а слово «last-child» более понятное, и кроме того, я придерживаюсь соглашения, когда марджины идут слева-направо (margin-right), сверху-вниз (margin-bottom), что соответствует русскому письму, кроме последних элементов, у которых этих марджинов нет, благодаря :not. Поэтому использование margin-top неприемлемо, в данном случае. Но ваш пример интересный.


        1. Spaceoddity
          29.05.2019 22:50

          Да что же вы такое городите?))
          А как же семантика? Надо же вначале общие стили прописать, а потом всякую специфику. А вы это всё в одну цепочку селекторов пихаете. Last-child не подцепит прописанный отступ, зато может подцепить дефолтный. Или мы юзаем какой-нибудь normalize.css? Тогда в чём профит от такой сокращенной, но не очевидной записи?


        1. melnik909 Автор
          29.05.2019 22:59

          «марджины идут слева-направо (margin-right), сверху-вниз (margin-bottom)» Можете подсказать, где прочитать про это соглашение?


          1. Spaceoddity
            30.05.2019 03:44

            Ну это видимо сокращенная запись «margin:» (начиная с «margin-top» и по часовой) установленная W3C в качества стандарта. Только наоборот и в зеркальном отражении.


          1. Manyaka
            30.05.2019 05:50

            Например, тут на хабре: Организация отступов в верстке (margin/padding). Такая организация — не идея автора той статьи. Вот, некоторые англоязычные источники, в которых есть размышления на эту тему: Single-direction margin declarations, margin-bottom or margin-top. Вот статья в поддержку margin-top: CSS: margin top vs bottom


            1. Spaceoddity
              30.05.2019 07:32

              Да это же дичь какая-то))
              Вот и выросло поколение верстальщиков, которые если и слышали о «схлопывании отступов», то по крайней мере не имеют представления как это используется.


            1. melnik909 Автор
              30.05.2019 09:34

              Manyaka Спасибо!