Сделать липкий элемент со скрытым переполнением - PullRequest
0 голосов
/ 23 апреля 2020

Как сделать липкий элемент со скрытым переполнением, развернуть, чтобы заполнить родительский элемент, у которого прокрутка при переполнении?

Незначительный пример:

.wrap {
  position: absolute;
  width: 250px;
  height: 80px;
  overflow: scroll;
  background: #844;
}
.stick {
  position: sticky;
  white-space: nowrap;
  overflow: hidden;
  background: #484;
  top: 0;
}
.text {
  color: #ccc;
}

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 10 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
  Hello and good bye to the sticky scroll once the wrap area scrolls past the initial width
a
b
c
d
e
f
g
h

Здесь зеленая линия липкая, но она не заполняет ширину элемента прокрутки, что пытаюсь добиться. Эффект виден после запуска прокрутки. Я могу решить это с помощью JS, но в надежде сделать это с помощью CSS.

Липкий элемент скрыт переполнением, поскольку в реальном коде в качестве подэлемента содержит широкий холст. Этот элемент шире, чем содержимое, как в «тексте» выше, и не должен быть видимым за пределами размера «текста».

Изображение:

enter image description here

  • Желтая часть закреплена сверху: прокрутите вверх / вниз, чтобы остаться сверху.
  • Желтая часть прокручивается влево / вправо. Следует за синим содержимым влево / вправо.
  • Желтая часть не расширяет синюю часть / просматриваемое содержимое Переполнение AKA скрыто.
  • Желтая часть имеет полную ширину синей части

Итак, желтая наклейка должна:

  1. иметь такую ​​же ширину, что и синий. Все, что находится за этим скрытым
  2. Оставайтесь в верхней части окна просмотра, если окно прокручивается вверх / вниз
  3. Следуйте содержимому влево / вправо

В реальном проекте Я использую его в макете MDI с несколькими абсолютными позициями "windows", имеющими один липкий элемент сверху и слева от области содержимого. Как, например, когда у вас есть открытая картинка в GIMP. (Пиксельные полосы). Слишком сложно разместить код для него, но вот небольшой макет:

Размер «окна» можно изменить, перетащив элемент в нижний правый угол.

(function() {
  "use strict";

  const spacer = {
    el: null,
    sz: {
      small: [100, 100],
      wide: [1000, 100],
      high: [100, 1000],
      big: [1000, 1000]
    },
    change: function (ev) {
      let z = spacer.sz[ev.target.value];
      spacer.el.style.width = z[0] + 'px';
      spacer.el.style.height = z[1] + 'px';
    },
    init: function () {
      spacer.el = document.querySelector('.content-spacer');
      spacer.el.addEventListener('change', spacer.change);
    }
  };

  const resizer = {
    el: null,
    overlay: null,
    move: function (ev) {
      ev.preventDefault();
      ev.stopPropagation();
      resizer.el_rz.style.marginTop = (ev.layerY - resizer.pos[0]) + 'px';
      resizer.el_rz.style.marginLeft = (ev.layerX - resizer.pos[1]) + 'px';
    },
    end: function () {
      window.removeEventListener('mousemove', resizer.move);
      window.removeEventListener('mouseup', resizer.end);
      resizer.overlay.style.display = 'none';

    },
    start: function (ev) {
      let t = ev.target,
          cs = getComputedStyle(t)
      ;
      ev.preventDefault();
      ev.stopPropagation();
      resizer.el_rz = ev.target;

      resizer.pos = [
        ev.clientX - (parseInt(cs.marginLeft) || 0),
        ev.clientY - (parseInt(cs.marginTop) || 0),
      ];
      window.addEventListener('mouseup', resizer.end);
      window.addEventListener('mousemove', resizer.move);
      resizer.overlay.style.display = 'block';
    },
    init: function () {
      resizer.el = document.getElementById("sizer");
      resizer.overlay = document.getElementById("overlay");
      resizer.el.addEventListener('mousedown', resizer.start);
    }
  };
  
  function fill_numbers(el) {
      let i, s = '';
      for (i = 1; i < 500; ++i)
        s += (i % 10) + ' ';
      el.textContent = s;
  }
  
  resizer.init();
  spacer.init();

  fill_numbers(document.querySelector('.top-line-c'));
  fill_numbers(document.querySelector('.left-line-c'));
})();
body {
  position            : relative;
  width               : 100vw;
  height              : 100%;
  padding             : 0;
  margin              : 0;
}
#overlay {
  position            : absolute;
  display             : none;
  z-index             : 100;
  height              : 100vh;
  width               : 100vw;
  opacity             : 0.1;
  background          : #333;
  z-index             : 100;
  cursor              : move;
}
.window {
  position            : absolute;
  overflow            : hidden;
  margin-top          : 5px;
  margin-left         : 5px;
  min-width           : 10px;
  min-height          : 10px;
  background          : #988;
  padding             : 0;
}
.sizer {
  position            : relative;
  background          : #8a8;
  bottom              : 0;
  right               : 0;
  width               : 15px;
  height              : 15px;
  margin-top          : 120px;
  margin-left         : 250px;
  cursor              : move;
}
.wrap {
  position            : relative;
  background          : #565;
  width               : 100%;
  height              : 100%;
}
.content-outer {
  overflow            : hidden;
  top                 : 0;
  bottom              : 0;
  right               : 0;
  left                : 0;
  position            : absolute;
  background          : #a77;
  padding             : 0;
}
.corner {
  position            : sticky;
  width               : 25px;
  height              : 25px;
  top                 : 0;
  left                : 0;
  z-index             : 150;
  background          : red;
}
.top-line {
  top                 : 0;
  margin-top          : -25px;
  margin-left         : 25px;
  position            : sticky;
  height              : 25px;
  background          : pink;
  width               : 100%;

  white-space         : nowrap;
  z-index             : 100;
  overflow            : hidden;
}
.left-line {
  position            : sticky;
  max-height          : 100%;
  overflow            : hidden;
  background          : #494;
  width               : 25px;
  left                : 0;
  z-index             : 100;
  text-align          : center;
}
.left-line-c {
  height              : 5000px;
}
.content-inner {
  position            : absolute;
  overflow            : scroll;
  top                 : 25px;
  right               : 0;
  bottom              : 0;
  left                : 0;
}
.content-text {
  position            : absolute;
  top                 : 0;
  left                : 0;
  right               : 0;
  bottom              : 0;
  margin              : 25px ;
}
.content-spacer {
  background: rgb(186,124,13);
  background: linear-gradient(90deg, rgba(186,124,13,1) 0%, rgba(112,25,58,0.9037815809917717) 53%, rgba(181,0,255,1) 100%);
  margin              : 15px;
  width               : 1000px;
  height              : 100px;
}
ul {
  list-style          : none;
  margin              : 0;
  padding             : 0;
}
.header {
  background          : #000;
  color               : #aaa;
  height              : 25px;
}
<div id="overlay"></div>
<div class="wrap">
    <div class="window">
        <div class="content-outer">
            <div class="header"><span>Header</span></div>
            <div class="content-inner">
                <div class="corner">C</div>
                <div class="top-line">
                  <div class="top-line-c"></div>
                </div>
                <div class="left-line">
                  <div class="left-line-c"></div>
                </div>
                <div class="content-text">
                  <div class="content-spacer">
                    <ul>
                      <li><label><input type="radio" name="sp" value="small">small</label></li>
                      <li><label><input type="radio" name="sp" value="wide" checked>wide</label></li>
                      <li><label><input type="radio" name="sp" value="high">high</label></li>
                      <li><label><input type="radio" name="sp" value="big">big</label></li>
                    </ul>
                  </div>
                </div>
            </div>
        </div>
        <div class="sizer" id="sizer" tabindex="0"></div>
    </div>
</div>

1 Ответ

0 голосов
/ 23 апреля 2020

Посмотрите, нужно ли вам это:

.wrap {
  position: absolute;
  width: 250px;
  height: 80px;
  overflow: scroll;
  background: #844;
}

.stick {
  position: sticky;
  display: table;
  white-space: nowrap;
  overflow: hidden;
  background: #484;
}

.text {
  color: #ccc;
}

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 10 21 22 23 24 25 26 27 28 29 30 31 32 33
  Hello and good bye to the sticky scroll once the wrap area scrolls past the initial width

Это будет расширение child <div> до общего содержания parent <div>.

Ниже того же примера со вторым фрагментом кода:

(function() {
  "use strict";

  const spacer = {
    el: null,
    sz: {
      small: [100, 100],
      wide: [1000, 100],
      high: [100, 1000],
      big: [1000, 1000]
    },
    change: function (ev) {
      let z = spacer.sz[ev.target.value];
      spacer.el.style.width = z[0] + 'px';
      spacer.el.style.height = z[1] + 'px';
    },
    init: function () {
      spacer.el = document.querySelector('.content-spacer');
      spacer.el.addEventListener('change', spacer.change);
    }
  };

  const resizer = {
    el: null,
    overlay: null,
    move: function (ev) {
      ev.preventDefault();
      ev.stopPropagation();
      resizer.el_rz.style.marginTop = (ev.layerY - resizer.pos[0]) + 'px';
      resizer.el_rz.style.marginLeft = (ev.layerX - resizer.pos[1]) + 'px';
    },
    end: function () {
      window.removeEventListener('mousemove', resizer.move);
      window.removeEventListener('mouseup', resizer.end);
      resizer.overlay.style.display = 'none';

    },
    start: function (ev) {
      let t = ev.target,
          cs = getComputedStyle(t)
      ;
      ev.preventDefault();
      ev.stopPropagation();
      resizer.el_rz = ev.target;

      resizer.pos = [
        ev.clientX - (parseInt(cs.marginLeft) || 0),
        ev.clientY - (parseInt(cs.marginTop) || 0),
      ];
      window.addEventListener('mouseup', resizer.end);
      window.addEventListener('mousemove', resizer.move);
      resizer.overlay.style.display = 'block';
    },
    init: function () {
      resizer.el = document.getElementById("sizer");
      resizer.overlay = document.getElementById("overlay");
      resizer.el.addEventListener('mousedown', resizer.start);
    }
  };
  
  function fill_numbers(el) {
      let i, s = '';
      for (i = 1; i < 500; ++i)
        s += (i % 10) + ' ';
      el.textContent = s;
  }
  
  resizer.init();
  spacer.init();

  fill_numbers(document.querySelector('.top-line-c'));
  fill_numbers(document.querySelector('.left-line-c'));
})();
body {
  position            : relative;
  width               : 100vw;
  height              : 100%;
  padding             : 0;
  margin              : 0;
}
#overlay {
  position            : absolute;
  display             : none;
  z-index             : 100;
  height              : 100vh;
  width               : 100vw;
  opacity             : 0.1;
  background          : #333;
  z-index             : 100;
  cursor              : move;
}
.window {
  position            : absolute;
  overflow            : hidden;
  margin-top          : 5px;
  margin-left         : 5px;
  min-width           : 10px;
  min-height          : 10px;
  background          : #988;
  padding             : 0;
}
.sizer {
  position            : relative;
  background          : #8a8;
  bottom              : 0;
  right               : 0;
  width               : 15px;
  height              : 15px;
  margin-top          : 120px;
  margin-left         : 250px;
  cursor              : move;
}
.wrap {
  position            : relative;
  background          : #565;
  width               : 100%;
  height              : 100%;
}
.content-outer {
  overflow            : hidden;
  top                 : 0;
  bottom              : 0;
  right               : 0;
  left                : 0;
  position            : absolute;
  background          : #a77;
  padding             : 0;
}
.corner {
  position            : sticky;
  width               : 25px;
  height              : 25px;
  top                 : 0;
  left                : 0;
  z-index             : 150;
  background          : red;
}
.top-line {
  top                 : 0;
  margin-top          : -25px;
  margin-left         : 25px;
  position            : sticky;
  height              : 25px;
  background          : pink;
  width               : 100%;
  display: table;
  white-space         : nowrap;
  z-index             : 100;
  overflow            : hidden;
}
.left-line {
  position            : sticky;
  max-height          : 100%;
  overflow            : hidden;
  background          : #494;
  width               : 25px;
  left                : 0;
  z-index             : 100;
  text-align          : center;
}
.left-line-c {
  height              : 5000px;
}
.content-inner {
  position            : absolute;
  overflow            : scroll;
  top                 : 25px;
  right               : 0;
  bottom              : 0;
  left                : 0;
}
.content-text {
  position            : absolute;
  top                 : 0;
  left                : 0;
  right               : 0;
  bottom              : 0;
  margin              : 25px ;
}
.content-spacer {
  background: rgb(186,124,13);
  background: linear-gradient(90deg, rgba(186,124,13,1) 0%, rgba(112,25,58,0.9037815809917717) 53%, rgba(181,0,255,1) 100%);
  margin              : 15px;
  width               : 1000px;
  height              : 100px;
}
ul {
  list-style          : none;
  margin              : 0;
  padding             : 0;
}
.header {
  background          : #000;
  color               : #aaa;
  height              : 25px;
}
<div id="overlay"></div>
<div class="wrap">
    <div class="window">
        <div class="content-outer">
            <div class="header"><span>Header</span></div>
            <div class="content-inner">
                <div class="corner">C</div>
                <div class="top-line">
                  <div class="top-line-c"></div>
                </div>
                <div class="left-line">
                  <div class="left-line-c"></div>
                </div>
                <div class="content-text">
                  <div class="content-spacer">
                    <ul>
                      <li><label><input type="radio" name="sp" value="small">small</label></li>
                      <li><label><input type="radio" name="sp" value="wide" checked>wide</label></li>
                      <li><label><input type="radio" name="sp" value="high">high</label></li>
                      <li><label><input type="radio" name="sp" value="big">big</label></li>
                    </ul>
                  </div>
                </div>
            </div>
        </div>
        <div class="sizer" id="sizer" tabindex="0"></div>
    </div>
</div>

Я только что добавил display: table; в класс .top-line.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...