Родитель с фиксированной высотой должен включать в себя ребенка с абсолютным / фиксированным положением - PullRequest
0 голосов
/ 30 сентября 2018

Я называю div.settings «родителем», а #mainMenu - «потомком».

Теперь я хочу создать выпадающий список, аналогичный выпадающему в Windows.Таким образом, высота родительского элемента должна быть фиксированной (как это было изначально).Кроме того, я хочу, чтобы мой ребенок был в состоянии fixed, чтобы иметь возможность создавать эффект ниже (я сам создам эффект позже).

enter image description here

Это то, что я сделал до сих пор.

* {
  box-sizing: border-box;
  cursor: default;
  user-select: none;
  font-family: Roboto;
  font-weight: 400;
}

.settings {
  padding: 7px 16px;
  border: 0.5px solid #7777;
  border-radius: 4px;
}

#mainMenu {
  position: fixed;
  /* or absolute */
  display: inline-flex;
  flex-flow: column wrap;
  justify-content: flex-start;
  align-items: stretch;
}

span.opt {
  padding: 5px 20px;
  flex-grow: 1;
  margin: 0;
  background: #777;
  color: #FFF;
  text-align: center;
  display: none;
}

span.selected {
  display: inline-block !important;
  background: #28F;
}

#mainMenu:hover>span.opt {
  display: inline-block;
}
<div class='settings'>
  <p>Select default browser</p>
  <span id='mainMenu'>
    <span class='opt'>Google Chrome</span>
    <span class='opt'>Mozilla Firefox</span>
    <span class='opt'>Safari</span>
    <span class='opt selected'>Microsoft Edge</span>
    <span class='opt'>Opera</span>
    <span class='opt'>Internet Explorer</span>
  </span>
</div>

Задача

Фиксированный дочерний элемент переполнен из тела своего родителя.

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

enter image description here

Красная линия (приблизительно) указывает, где должна быть граница родителя.

Примечание : только CSS (потому что без эффекта нет ничего динамического), и я отобразил только одно из меню в моем коде (чтобы минимизировать сложность и длину кода).В действительности, может быть много .

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

Ответы [ 4 ]

0 голосов
/ 21 октября 2018

Предложение по JavaScript и CSS Solution

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

function setTop() {
  let height = document.querySelector(".opt").clientHeight;
  document.querySelector(".options").style.top = height * 3 * (-1) + "px";
}
setTop();
* {
      box-sizing: border-box;
      cursor: default;
      user-select: none;
      font-family: Roboto;
      font-weight: 400;
    }

    .settings {
      padding: 7px 16px;
      border: 0.5px solid #7777;
      border-radius: 4px;
    }

    #mainMenu {
      position: relative;
      display: block;
      width:300px;
    }
    #mainMenu .options {
      position: absolute;
      display: none;
      width:100%;
    }
    #mainMenu:hover .options {
      display: block;
    }

    #mainMenu .opt {
      padding: 5px 20px;
      background: #777;
      color: #FFF;
      text-align: center;
    }
    #mainMenu .opt.selected {
      background: #28F;
    }
    #mainMenu .selection {
      display:block;
    }
<div class='settings'>
      <p>Select default browser</p>
      <div id='mainMenu'>
        <span class='opt selected selection'>Microsoft Edge</span>
        <div class='options' style="top:0;">
          <div class='opt'>Google Chrome</div>
          <div class='opt'>Mozilla Firefox</div>
          <div class='opt'>Safari</div>
          <div class='opt selected'>Microsoft Edge</div>
          <div class='opt'>Opera</div>
          <div class='opt'>Internet Explorer</div>
        </div>
      </div>
    </div>
0 голосов
/ 20 октября 2018

Вы можете обернуть ваши меню в div с минимальной высотой, чтобы сохранить это пространство в родительском div, или , используя "placeholder" span.opt.selected с видимостью: hidden (см. Обновленный фрагмент).

* {
  box-sizing: border-box;
  cursor: default;
  user-select: none;
  font-family: Roboto;
  font-weight: 400;
}

.settings {
  padding: 7px 16px;
  border: 0.5px solid #7777;
  border-radius: 4px;
  background-color: inherit;
}

#mainMenu {
  position: fixed;
  /* or absolute */
  display: inline-flex;
  flex-flow: column wrap;
  justify-content: flex-start;
  align-items: stretch;
}

span.opt {
  padding: 5px 12px;
  flex-grow: 1;
  margin: 0;
  background: #777;
  color: #FFF;
  text-align: center;
  display: none;
}

span.placeholder {
  visibility: hidden;
}

span.selected {
  display: inline-block !important;
  background: #28F;
}

#mainMenu:hover>span.opt {
  display: inline-block;
}
<div class='settings'>
  <p>Select default browser</p>
  <span id='mainMenu'>
    <span class='opt'>Google Chrome</span>
    <span class='opt'>Mozilla Firefox</span>
    <span class='opt'>Safari</span>
    <span class='opt selected'>Microsoft Edge</span>
    <span class='opt'>Opera</span>
    <span class='opt'>Internet Explorer</span>
  </span>
  <span class='opt selected placeholder'>placeholder</span>
</div>
0 голосов
/ 21 октября 2018

Я хочу, чтобы родитель включил меню в свой контент

Добавление позиции absolute или fixed в меню выводит его из потока контента, поэтому вы выиграли 'Получите нужный макет без небольшой реструктуризации HTML.

Демонстрация добавлена ​​ниже, дайте мне знать, если у вас есть какие-либо вопросы.Вам нужно будет добавить дополнительную логику, чтобы проверить, находится ли меню за пределами области просмотра.

const MENU = document.getElementById('mainMenu');
const SELECTION = document.getElementById('selection');
const OPTION_CONTAINER = document.getElementById('options');
const OPTIONS = [...document.querySelectorAll('.opt')];

let height;

function addEventListeners() {
  OPTIONS.forEach((option, index) => {
    option.addEventListener('click', (e) => {
      let val = option.innerText;
      SELECTION.innerText = val;
      positionMenu(index);

      if (MENU.classList.contains('is-open')) {
        MENU.classList.remove('is-open')
      }
    })
  })

  MENU.addEventListener('mouseenter', () => {
    MENU.classList.add('is-open');
  })

  MENU.addEventListener('mouseleave', () => {
    MENU.classList.remove('is-open');
  })
}

function getOptionHeight() {
  height = OPTIONS[0].getBoundingClientRect().height;
}

function positionMenu(index) {
  index--;
  OPTION_CONTAINER.style.transform = `translateY(-${index * height}px)`;
}

getOptionHeight();
addEventListeners();
* {
  box-sizing: border-box;
  cursor: default;
  user-select: none;
  font-family: Roboto;
  font-weight: 400;
}

.settings {
  /* demo */
  margin: 100px 0 100px;
  
  padding: 7px 16px;
  border: 0.5px solid #7777;
  border-radius: 4px;
}

.options-container {
  position: relative;
  width: 200px;
}

.options {
  display: inline-flex;
  flex-flow: column wrap;
  justify-content: flex-start;
  align-items: stretch;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  opacity: 0;
  pointer-events: none;
}

.opt {
  padding: 5px 20px;
  flex-grow: 1;
  margin: 0;
  background: #777;
  color: #FFF;
  text-align: center;
  display: inline-block;
  width: 100%;
}

.selected {
  background: #28F;
}

.options-container.is-open .options {
  opacity: 1;
  pointer-events: auto;
}

.opt:hover {
  background: #28F;
}
<div class='settings'>
  <p>Select default browser</p>
  <div id='mainMenu' class="options-container">
    <span id="selection" class="opt selected">Select</span>
    <div class="options" id="options">
      <span class='opt'>Google Chrome</span>
      <span class='opt'>Mozilla Firefox</span>
      <span class='opt'>Safari</span>
      <span class='opt'>Microsoft Edge</span>
      <span class='opt'>Opera</span>
      <span class='opt'>Internet Explorer</span>
    </div>
  </div>
</div>
0 голосов
/ 30 сентября 2018

Я добавил эффект наведения, чтобы вы могли видеть, что высота установки является динамической

var mainMenu = document.getElementById("mainMenu");
var heightc = document.getElementById("heightc");
var opt = document.getElementsByClassName("opt");
var scrollHeight = 0;
mainMenu.addEventListener('mouseenter', function(){
    for(var i=0; i<opt.length; i++){
       if(opt[i].className.indexOf("selected") > 0){
          var dm = i*opt[i].offsetHeight;
          mainMenu.style.bottom = dm + 'px';
          heightc.style.paddingBottom = dm + 'px';
          scrollHeight = window.scrollY;
          window.scrollTo(0, window.scrollY+dm);
       }
    }
});


mainMenu.addEventListener('mouseleave', function(){
    mainMenu.style.bottom = 0;
    heightc.style.paddingBottom = 0;
    window.scrollTo(0, scrollHeight); 
});
* {
	box-sizing: border-box;
	cursor: default;
	user-select: none;
	font-family: Roboto;
	font-weight: 400;
}
#fs{
  height: 1000px;
}
.settings {
	padding: 7px 16px;
	border: 0.5px solid #7777;
	border-radius: 4px;
}
#mainMenu {
	display: inline-flex;
	flex-flow: column wrap;
	justify-content: flex-start;
	align-items: stretch;
  position: relative;
}
/* added */
#mainMenu span{
  display: none;
}
#mainMenu .selected{
  display: block;
}
#mainMenu:hover .opt{
  display: block;
}
/* end added */
span.opt {
	padding: 5px 12px;
	flex-grow: 1;
	margin: 0;
	background: #777;
	color: #FFF;
	text-align: center;
}
span.selected {
	display: inline-block !important;
	background: #28F;
}
<div class='settings'>
  <p id="heightc">Select default browser</p>
  <span id='mainMenu'>
    <span class='opt'>Google Chrome</span>
    <span class='opt'>Mozilla Firefox</span>
    <span class='opt'>Safari</span>
    <span class='opt selected'>Microsoft Edge</span>
    <span class='opt'>Opera</span>
    <span class='opt'>Internet Explorer</span>
  </span>
</div>
<div id="fs"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...