Как добавить верхнюю и нижнюю тень во время прокрутки, но только при необходимости?

Как добавить тень при переполнении контейнера, но только при необходимости?

Я имею в виду:

  • если доступно содержание для прокрутки сверху или снизу, покажите тень, чтобы сообщить пользователю, что есть больше контента для scoll
  • Если нет прокрутки контента, тень не появится

И уточнить далее

  • если содержимое контейнера переполняется (т.е. оно прокручивается), а пользователь находится на самой верхней части содержимого, тогда в нижней части страницы должна быть тень, а не верх.
  • То же самое происходит, если пользователь находится в нижней части страницы, ожидая, что в верхней части будет тень.
  • Если содержимое не переполняет контейнер, то не следует показывать тень, чтобы сохранить чистоту.

У меня есть рабочие javascript-решения, но я хочу что-то чисто css по соображениям производительности.

Любые идеи?

Ответ 1

Я думаю, что вы ищете что-то вроде этого;

Ссылка: ССЫЛКА

html {
  background: white;
  font: 120% sans-serif;
}

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 200px;
  margin: 50px auto;
  background: /* Shadow covers */
  linear-gradient(white 30%, rgba(255, 255, 255, 0)), linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, /* Shadows */
  radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%;
  background: /* Shadow covers */
  linear-gradient(white 30%, rgba(255, 255, 255, 0)), linear-gradient(rgba(255, 255, 255, 0), white 70%) 0 100%, /* Shadows */
  radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%;
  background-repeat: no-repeat;
  background-color: white;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  /* Opera does not support this in the shorthand */
  background-attachment: local, local, scroll, scroll;
}
<div class="scrollbox">
  <ul>
    <li>I Show Below Shadow. Go Down Now</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>11</li>
    <li>12</li>
    <li>13</li>
    <li>14</li>
    <li>15</li>
    <li>16</li>
    <li>17</li>
    <li>18</li>
    <li>19</li>
    <li>20</li>
    <li>The end!</li>
    <li>No shadow here. See Above. Go Up</li>
  </ul>
</div>

Ответ 2

Извиняюсь за ответ на мой собственный вопрос, но после некоторого поиска в Google я нашел хорошее решение только для CSS, которое работает в chrome на macOS.

@Hash предоставил решение, взятое из блога lea verou. Ее решение использует background-attachment: local для достижения эффекта, однако в настоящее время это прерывается в chrome 59 на macOS?? (Он работал в 2012 году, но не в 2017 году для меня, по крайней мере, сейчас). Тем не менее, ее решение отличное, и вы должны прочитать подробнее об этом здесь.

В своей статье (с 2012 года) она ссылается на более старое, но более совместимое решение, в котором используются псевдоэлементы. Это сообщение в блоге от Романа Комарова и вот некоторые прямые цитаты из его статьи.

Вот старая идея, но воссозданная с чистым CSS.

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

Хотя этот метод прост, существуют некоторые ограничения:

  • фон должен быть твердым
    • однако, если вы попробуете background-attachment: fixed...)
  • есть некоторые проблемы с позиционированием

Но в большинстве случаев этот метод довольно пуленепробиваемый.

Если вы замените CSS-градиенты на простые изображения, этот метод может работать в IE. (Может потребоваться еще несколько небольших исправлений, я не проверял.)

И вот какой код скопирован непосредственно из его блога:

html {
  background: #FFF;
}

.scrollbox {
  position: relative;
  z-index: 1;
  overflow: auto;
  width: 200px;
  max-height: 200px;
  margin: 50px auto;
  background: #FFF no-repeat;
  background-image: -webkit-radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), -webkit-radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0));
  background-image: -moz-radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), -moz-radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0));
  background-image: radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0)), radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0));
  background-position: 0 0, 0 100%;
  background-size: 100% 14px;
}

.scrollbox:before,
.scrollbox:after {
  content: "";
  position: relative;
  z-index: -1;
  display: block;
  height: 30px;
  margin: 0 0 -30px;
  background: -webkit-linear-gradient(top, #FFF, #FFF 30%, rgba(255, 255, 255, 0));
  background: -moz-linear-gradient(top, #FFF, #FFF 30%, rgba(255, 255, 255, 0));
  background: linear-gradient(to bottom, #FFF, #FFF 30%, rgba(255, 255, 255, 0));
}

.scrollbox:after {
  margin: -30px 0 0;
  background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0), #FFF 70%, #FFF);
  background: -moz-linear-gradient(top, rgba(255, 255, 255, 0), #FFF 70%, #FFF);
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), #FFF 70%, #FFF);
}
<div class="scrollbox">
    <ul>
        <li>Not enough content to scroll</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
</div>


<div class="scrollbox">
    <ul>
        <li>Ah! Scroll below!</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>The end!</li>
        <li>No shadow there.</li>
    </ul>
</div>

Ответ 3

Вот чистое CSS-решение, которое я собрал, которое ставит тень на контент, а не за ним.

/* Stuff that does not matter */

html {
  font-size: 16px;
}

body {
  margin: 0;
  padding: 0;
  font: 1rem/1.5 arial, sans-serif;
}

.c-container {
  width: 100%;
  max-width: 400px;
  margin: 0 auto;
  padding: 0 2rem;
  box-sizing: border-box;
}

.c-header {
  width: 100%;
  padding: 1rem 0;
  background: white;
}

.c-header_heading {
  margin: 0;
  font-size: 2rem;
  font-weight: bold;
}

/* Stuff that matters */

.c-scrollbox {
  position: relative;
  width: 100%;
  height: 200px;
  overflow: scroll;
}

.c-scrollbox::before {
  content: '';
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  display: block;
  height: 1px;
  background: rgba(0,0,0,.32);
}

.c-scrollbox::after {
  content: '';
  position: absolute;
  top: 0;
  display: block;
  width: 100%;
  height: 1rem;
  background: linear-gradient(rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%);
}
<div class="c-container">
  <header class="c-header">
    <h1 class="c-header_heading">Shadow on Scroll</h1>
  </header>
  <div class="c-scrollbox">
    <p>Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ullamcorper nulla non metus auctor fringilla. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p>
    <p>Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
    <p>Vestibulum id ligula porta felis euismod semper. Nullam quis risus eget urna mollis ornare vel eu leo. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nullam quis risus eget urna mollis ornare vel eu leo. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Nulla vitae elit libero, a pharetra augue. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p>
  </div>
</div>