Выровнять один элемент списка по центру CSS - PullRequest
0 голосов
/ 04 мая 2018

Я создаю панель навигации в Reactjs с четырьмя элементами. Эти элементы представляют собой простой неупорядоченный список с некоторыми CSS, использующими flexbox для выравнивания по горизонтали.

<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
<ul/>

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

The selected item appear in the center row

Ниже приводится тег css для <ul>.

ul {
    list-style-type: none;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
}

Я пытался использовать align-self: center на одном из <li> предметов, но безуспешно.

У кого-нибудь есть опыт создания чего-то подобного? Я открыт для всех типов решений, даже для тех, которые не используют flexbox.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

У элементов списка есть фиксированное значение, и знаете ли вы, сколько элементов есть? Если это так, вы можете вычислить центр списка, смещение элемента и добавить CSS-преобразование.

Пример:

  • У вас есть список из четырех предметов.
  • Каждый элемент имеет ширину, равную 100 пикселей.
  • Таким образом, общая ширина списка составляет 400 пикселей.
  • Центральная точка списка составляет 200 пикселей слева.
  • Центральная точка позиции номер два - 150 пикселей слева. Поэтому мы должны переместить список на 200 - 150 пикселей = 50 пикселей влево.
  • Центральная точка позиции номер четыре - 350 пикселей слева. Поэтому мы должны переместить список на 200 - 350 пикселей = -150 пикселей слева.

Если ваш список динамический, как в отношении длины списка, так и ширины элемента, вы можете использовать Element.getBoundingClientRect () , чтобы найти размеры элементов, и использовать те же вычисления, что и выше.

Codepen: https://codepen.io/anon/pen/vjJMVL

HTML:

<ul class="selected-2">
  <li>1</li>
  <li class="selected">2</li>
  <li>3</li>
  <li>4</li>
</ul>

<ul class="selected-4">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="selected">4</li>
</ul>

CSS:

ul {
  display: flex;
  justify-content: center;
  list-style: none;
}

li {
  width: 80px;
  height: 80px;
  background-color: #eee;
  margin: 10px;
}

.selected {
  background-color: #ccc;
}

.selected-2 {
  transform: translateX(50px)  
}

.selected-4 {
  transform: translateX(-150px)  
}
0 голосов
/ 04 мая 2018

Рассчитайте <MenuItem> центр, по которому щелкнули, используя Element.getBoundingClientRect(), чтобы получить left и width, и передайте его родителю (<Menu>). В родителе используйте ссылку <ul> s, чтобы получить left и ширину с Element.getBoundingClientRect(). Вычислите состояние moveTo и обновите стиль <ul> s transform: translateX() соответственно:

const { Component } = React;
const items = ['One', 'Two', 'Three', 'Four'];

class MenuItem extends Component {
  clickHandler = (e) => {
    const { left, width } = e.target.getBoundingClientRect();
    const itemCenter = left + width / 2;
    this.props.updateCenter(itemCenter);
  }

  render() {
    const { children } = this.props;
    
    return (
      <li onClick={this.clickHandler}>{children}</li>
    );
  }
}

class Menu extends Component {
  state = {
    moveTo: 0
  };
  
  updateCenter = (itemCenter) => {
    const { left, width } = this.ul.getBoundingClientRect();
    
    //this.ul.style.transform = `translateX(${center}px)`;
    
    this.setState(() => ({
      moveTo: left + width / 2 - itemCenter
    }));
  };

  render() {
    const { items } = this.props;
    const { moveTo } = this.state;
    
    return (
      <nav>
        <ul ref={(ul) => this.ul = ul} style={{
          transform: `translateX(${moveTo}px)`
        }}>
        {
          items.map((text) => (
            <MenuItem key={text} 
              updateCenter={this.updateCenter}>
              {text}
            </MenuItem>
          ))
        }
        </ul>
      </nav>
    );
  }
}

ReactDOM.render(
  <Menu items={items} />,
  demo
);
/** demo only - display the center **/
body::before {
  position: absolute;
  left: 50%;
  height: 100vh;
  border-right: 1px solid black;
  content: '';
}

nav {
  overflow: hidden;
}

ul {
  list-style-type: none;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: center;
  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

li {
  padding: 1em;
  border: 1px solid black;
  cursor: pointer;
}

ul li:not(:last-child) {
  margin: 0 1em 0 0;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="demo"></div>
0 голосов
/ 04 мая 2018

Так как я не получаю полностью то, что вы хотите, это лучшее, что я мог бы придумать, применяя абсолютное позиционирование к выбранному и перекрывая другие с помощью z-index

document.querySelectorAll('li').forEach(function(li){
	li.addEventListener('click',function(e){
		document.querySelectorAll('li').forEach(function(obj){
			obj.classList.remove('selected');
		});
		e.target.classList.add("selected");		
	});
});
ul {
    list-style-type: none;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
}


li{
    border:1px solid;
    padding:10px;
    cursor:pointer;
    position:relative;
    transition:all ease 1s;
    margin:0 20px;
}


.selected{
    transform:scale(2.1);
    background:white;
    box-shadow:0px 0px 55px black;
    position:absolute;
    z-index:5;
}
<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
</ul>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...