首页 > 解决方案 > 使用变换在窗口上居中元素

问题描述

我试图在单击卡片元素时将其居中,以突出显示它并使用 CSS 转换将其与其他卡片分开。我知道 CSS 变换是相对于元素的位置的,但我必须使用变换而不是顶部/左侧以避免重新定位其他卡片。我尝试使用 JavaScript 计算正确的偏移量,如下所示:

const cardRect = cardElement.getBoundingClientRect();

const offsetX = window.innerWidth / 2 - cardRect.x - cardRect.width / 2;
const offsetY = window.innerHeight / 2- cardRect.y - cardRect.height / 2;

然而这并没有奏效,因为边界客户端矩形一直在变化,因为我在卡片悬停时有一个比例(1.1)。

那么如何将点击的卡片移动到中心,而不抵消所有其他卡片呢?

这些卡片在 HTML 中是这样创建的:

<div class='container'>

  <div class='movie'>
    <img :src='/images/1.png'>
    <h3>Harry Potter and the Sorcerer's Stone</h3>
  </div>

  <div class='movie'>
    <img :src='/images/2.png'>
    <h3>Harry Potter and the Chamber of Secrets</h3>
  </div>

  <div class='movie'>
    <img :src='/images/3.png'>
    <h3>Harry Potter and the Prisoner of Azkaban</h3>
  </div>
  
  etc...

</div>

一切的风格都是这样的:

.container {
  display: flex;
  flex-flow: row wrap;
}

.movie {
  width: min-content;
  flex: 1;
}

.movie:not(.selected-movie):hover { /* .selected-movie is a class applied to the clicked card */
  transform: scale(1.1);
  box-shadow: 10px 10px 32px 0px rgba(0,0,0,0.4),
              -10px -10px 32px 0px rgba(0,0,0,0.4);
}

.selected-movie {
  transform: translate(offsetX, offsetY); /* Here are the offsets needed */
  flex: 0;
  display: grid;
  grid-template-areas:
      'poster title'
      'poster description';
}

这是一个显示问题的 JSFiddle:https ://jsfiddle.net/u6tpbjna/5/

标签: javascripthtmlcss

解决方案


当点击的电影被选中时,你的一些其他 CSS 样式.selected-movie会丢弃未选择的卡片样式,所以我暂时注释掉了这些样式。无论如何,我相信这应该回答您询问的关于在 CSS 中使用这些偏移量的问题。

这是使用 CSS 变量的绝佳机会,您可以使用 JavaScript 在页面加载和窗口调整大小时设置这些变量。从那里开始,其他一切都可以在 CSS 中完成。

见下文:

const cards = Array.from(document.querySelectorAll('.movie'));

const setCardOffsets = () => {
  for (card of cards) {
    const cardRect = card.getBoundingClientRect();
    const cardOffsetX = window.innerWidth / 2 - cardRect.x - cardRect.width / 2;
    const cardOffsetY = window.innerHeight / 2- cardRect.y - cardRect.height / 2;
    card.style.setProperty('--offset-x', cardOffsetX + "px");
    card.style.setProperty('--offset-y', cardOffsetY + "px");
  }
}
setCardOffsets();
window.onresize = setCardOffsets;

document.addEventListener('click', e => {
  if (e.target && e.target?.matches('.movie, .movie *')) {
    const clickedCard = e.target.matches('.movie') ? e.target : e.target.closest('.movie');
    if (clickedCard.classList.contains('selected-movie')) {
      clickedCard.classList.remove('selected-movie');
      return;
    }
    cards.forEach(card => card.classList.remove('selected-movie'));
    clickedCard.classList.add('selected-movie');
  }
});
.container {
  display: flex;
  flex-flow: row wrap;
}

.movie {
  transform: scale(1) translate(0px, 0px);
  width: min-content;
  flex: 1;
  position: relative;
  transition: all 0.2s ease-out;
}

.movie:not(.selected-movie):hover {
  transform: scale(1.1) translate(0px, 0px);
  box-shadow: 10px 10px 32px 0px rgba(0,0,0,0.4),
              -10px -10px 32px 0px rgba(0,0,0,0.4);
  z-index: 2;
}

.selected-movie {
  transform: scale(1.1) translate(var(--offset-x), var(--offset-y));
  /*flex: 0;
  display: grid;
  grid-template-areas:
      'poster title'
      'poster description';*/
  z-index: 1;
}
<div class='container'>

  <div class='movie'>
    <img src='/images/1.png'>
    <h3>Harry Potter and the Sorcerer's Stone</h3>
  </div>

  <div class='movie'>
    <img src='/images/2.png'>
    <h3>Harry Potter and the Chamber of Secrets</h3>
  </div>

  <div class='movie'>
    <img src='/images/3.png'>
    <h3>Harry Potter and the Prisoner of Azkaban</h3>
  </div>

</div>

我希望这有帮助!如果您对我的实施有任何疑问,请告诉我。


推荐阅读