#javascript #html #css
#javascript #HTML #css
Вопрос:
Как использовать scrollIntoView в контейнере, который имеет overflow:hidden
и не должен прокручивать страницу?
Вот пример: внизу страницы текст в контейнере <div class="cnt'>
с фиксированной шириной и скрытым переполнением. Я хочу прокручивать элементы в этом контейнере без прокрутки страницы.
В верхней части страницы две кнопки для прокрутки до первого и последнего элемента. Если я нажму на кнопку, она будет прокручивать текст в контейнере и переходить к этому контейнеру внизу страницы.
Я не могу использовать scrollLeft, потому что переполнение скрыто. 🙁
Кто-нибудь знает, как это решить?
const cnt = document.querySelector('.cnt')
const spanElements = cnt.querySelectorAll('span');
const lastSpan = spanElements[spanElements.length - 1]
const firstSpan = spanElements[0]
lastSpan.scrollIntoView()
const buttons = Array.from(document.querySelectorAll('button'))
const [buttonToFirstEl, buttonToLastEl] = buttons;
buttonToFirstEl.onclick = function() {
firstSpan.scrollIntoView()
}
buttonToLastEl.onclick = function() {
lastSpan.scrollIntoView()
}
.cnt {
width: 90px;
overflow: hidden;
white-space: nowrap;
padding: 8px;
border: solid #ccc 1px;
}
.filler {
width: 100%;
height: 200px;
border: dashed 2px #ccc;
margin: 20px;
}
.root {
border: solid 1px;
}
<div class="root">
<button id="button">scroll to first element</button>
<button id="button">scroll to last element</button>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="cnt">
<span>
first:tessst
</span>
<span>
2:dddd
</span>
<span>
3:cccddd
</span>
<span>
4:rreeee
</span>
<span>
last:dddrreddd
</span>
</div>
</div>
Комментарии:
1. вы хотите, чтобы в div .root была скрыта прокрутка Y с переполнением, верно
2. Вы хотите только поведение scrollIntoView по умолчанию или также иметь возможность передавать правила, встроенные в блок? Кроме того, вам важно писать указания или обрабатывать все как слева направо сверху вниз, это нормально?
3. @OuchaneCC Я хочу прокручивать элементы внутри <div class=»cnt»> . .корневой элемент, используемый для отображения этой страницы, тоже прокручивается
4. @Kaiido для этого примера поведение по умолчанию в порядке
Ответ №1:
если вы хотите прокручивать элемент в классе .cnt
- вам нужно стилизовать каждый интервал в .cnt
.cnt span{
/* relative block for make elements solid amp; listed*/ position : relative; display : block;
color: red; font-size : 16px;
}
- и в родительском файле .cnt вам нужно указать высоту, чтобы прокрутка работала
.cnt {
width: 90px;
/* for example 28px */
height : 28px;
overflow: hidden;
white-space: nowrap;
padding: 4px;
border: solid black 1px;
/* overflow y or x for making scroll*/
overflow-y : scroll;
}
- я надеюсь, что эти шаги помогут вам
Ответ №2:
Чтобы получить это правильно (т.Е. С поддержкой всех параметров режима записи, направления и встроенного блока), вам, по сути, придется переписать scrollIntoView с нуля, опустив цикл, который поднимается по дереву прокрутки. коробки. Это не тривиальная задача.
Если вам не нужно пуленепробиваемое решение, вы можете просто получить ближайшее окно прокрутки и проверить, насколько оно должно быть прокручено, чтобы показать начало вашего элемента:
const cnt = document.querySelector('.cnt')
const spanElements = cnt.querySelectorAll('span');
const lastSpan = spanElements[spanElements.length - 1]
const firstSpan = spanElements[0]
const buttons = Array.from(document.querySelectorAll('button'))
const [buttonToFirstEl, buttonToLastEl] = buttons;
buttonToFirstEl.onclick = function() {
scrollIntoParentView( firstSpan );
}
buttonToLastEl.onclick = function() {
scrollIntoParentView( lastSpan );
}
function scrollIntoParentView( elem, options ) {
const directions = getSimpleScrollIntoViewDirections( elem, options );
const left = directions.inline_direction || 0;
const top = directions.block_direction || 0;
const new_options = {
left,
top,
behavior: (options amp;amp; options.behavior) || "auto"
};
directions.scrolling_box.scrollBy( new_options );
}
function getSimpleScrollIntoViewDirections( elem, { block = "start", inline = "start" } = {} ) {
const element_bbox = elem.getBoundingClientRect();
const scrolling_box = getNearestScrollingBox( elem );
const scrolling_box_bbox = scrolling_box.getBoundingClientRect();
const block_direction = Math.round( element_bbox.top - scrolling_box_bbox.top);
const inline_direction = Math.round( element_bbox.left - scrolling_box_bbox.left);
return {
scrolling_box,
block_direction,
inline_direction
};
}
function getNearestScrollingBox( elem ) {
if( !elem.isConnected ) { return null; }
const elem_computed_styles = getComputedStyle( elem );
// not in specs, but that seems to be what browser implementations do
if( elem_computed_styles.getPropertyValue( 'position' ) === "fixed" ) {
return null;
}
const scrolling_box = elem.parentElement;
if( !scrolling_box ) {
return elem === document.scrollingElement ? null : document.scrollingElement;
}
const computed_styles = getComputedStyle( scrolling_box );
const scroll_x = computed_styles.getPropertyValue( "overflow-x");
const scroll_y = computed_styles.getPropertyValue( "overflow-y");
if(
(scroll_x === 'clip' amp;amp; scroll_y === 'clip') ||
(scrolling_box.offsetHeight <= scrolling_box.scrollingHeight) ||
(scrolling_box.offsetWidth <= scrolling_box.scrollingWidth)
) {
return getNearestScrollingBox( scrolling_box );
}
return scrolling_box;
}
.cnt {
width: 90px;
overflow: hidden;
white-space: nowrap;
padding: 8px;
border: solid #ccc 1px;
}
.filler {
width: 100%;
height: 200px;
border: dashed 2px #ccc;
margin: 20px;
}
.root {
border: solid 1px;
}
<div class="root">
<button id="button">scroll to first element</button>
<button id="button">scroll to last element</button>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="cnt">
<span>
first:tessst
</span>
<span>
2:dddd
</span>
<span>
3:cccddd
</span>
<span>
4:rreeee
</span>
<span>
last:dddrreddd
</span>
</div>
</div>
Ответ №3:
scrollLeft
и scrollTop
хорошо работать overflow:hidden
с. Я проверяю scrollLeft
свойство первого элемента span вместо его контейнера
изменение scrollLeft
родительского элемента span, решить эту проблему
firstSpan.parentElement.scrollLeft = 0;
const cnt = document.querySelector('.cnt')
const spanElements = cnt.querySelectorAll('span');
const lastSpan = spanElements[spanElements.length - 1]
const firstSpan = spanElements[0]
lastSpan.scrollIntoView()
const buttons = Array.from(document.querySelectorAll('button'))
const [buttonToFirstEl, buttonToLastEl] = buttons;
buttonToFirstEl.onclick = function() {
firstSpan.parentElement.scrollLeft = 0;
}
buttonToLastEl.onclick = function() {
const cnt = lastSpan.parentElement;
cnt.scrollLeft = cnt.scrollWidth;
}
.cnt {
width: 90px;
overflow: hidden;
white-space: nowrap;
padding: 8px;
border: solid #ccc 1px;
}
.filler {
width: 100%;
height: 200px;
border: dashed 2px #ccc;
margin: 20px;
}
.root {
border: solid 1px;
}
<div class="root">
<button id="button">scroll to first element</button>
<button id="button">scroll to last element</button>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="filler">
</div>
<div class="cnt">
<span>
first:tessst
</span>
<span>
2:dddd
</span>
<span>
3:cccddd
</span>
<span>
4:rreeee
</span>
<span>
last:dddrreddd
</span>
</div>
</div>