与缩放的同级保持一致,而无需反缩放

时间:2019-06-10 22:26:05

标签: html css css-transitions css-transforms

我有一个需要缩放背景的元素,而没有缩放父元素中的元素。我通过使用pseudo元素定义背景来实现这一点,然后在hover上我简单地缩放了pseudo元素。到目前为止,很好...

问题是,我需要一些元素来与缩放后的背景保持一致,尽管它们本身不会缩放。我最初的计划只是简单地translate,但是我很快意识到这是不可能的,因为scale是基于倍数的,而translate是基于百分比/像素等的。 / p>

显而易见的解决方案是报废scale,而使用margin缩小绝对定位的pseudo元素。但是,我对此保留意见是transition边距值是一个不好的做法。

有人能想到我可以使用scale并保持对齐的方式吗?

更新

我想不惜一切代价避免反向/反向缩放,因为在大多数情况下,反向缩放在浏览器中表现不佳。考虑到这一点,我认为这实际上是不可能的,但是如果有人知道一些CSS魔术,这将使问题悬而未决。

请参见以下代码段作为示例:

.tile {
  position: relative;
  width: 500px;
  height: 100px;
  padding: 40px;
}

.tile:hover:before {
  transform: scale(.9);
}

.tile:before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #000;
  z-index: -1;
  transition: transform .3s ease-out;
}

h1 {
  text-align: center;
  color: white;
}

.tile > .button {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-block;
  background: red;
  padding: 10px 15px;
  color: white;
}
<div class="tile">
  <h1>Hello World</h1>
  <div class="button">Align Me</div>
</div>

2 个答案:

答案 0 :(得分:1)

如果按p进行缩放,则将减小大小,新的宽度将变为width*(1 - p)。高度逻辑相同。您可以考虑使用calc(),并使用此公式轻松定义翻译。

我们除以2是因为我们从两边都减少了,所以我们将从1边进行翻译

.tile {
  position: relative;
  width: 540px;
  height: 200px;
  display:flex;
  align-items:center;
  justify-content:center;
}

.tile:hover:before {
  transform: scale(0.9);
}
.tile:hover .button{
  transform: translate(calc(-540px*0.1/2),calc(200px*0.1/2));
}
.tile:before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #000;
  z-index: -1;
  transition: transform .3s;
}

h1 {
  text-align: center;
  color: white;
  margin:0;
}

.tile > .button {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-block;
  background: red;
  padding: 10px 15px;
  color: white;
  transition: transform .3s ;
}
<div class="tile">
  <h1>Hello World</h1>
  <div class="button">Align Me</div>
</div>

您可以考虑使用CSS变量轻松更改比例值:

.tile {
  position: relative;
  width: 540px;
  height: 200px;
  display:flex;
  align-items:center;
  justify-content:center;
  --s:0.9;
}

.tile:hover:before {
  transform: scale(var(--s));
}
.tile:hover .button{
  transform: translate(calc(-540px*(1 - var(--s))/2),calc(200px*(1 - var(--s))/2));
}
.tile:before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #000;
  z-index: -1;
  transition: transform .3s;
}

h1 {
  text-align: center;
  color: white;
  margin:0;
}

.tile > .button {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-block;
  background: red;
  padding: 10px 15px;
  color: white;
  transition: transform .3s ;
}
<div class="tile">
  <h1>Hello World</h1>
  <div class="button">Align Me</div>
</div>

<div class="tile" style="--s:0.5">
  <h1>Hello World</h1>
  <div class="button">Align Me</div>
</div>

答案 1 :(得分:1)

尝试自行扩展.tile并反向扩展其子级:

.tile {
  position: relative;
  width: 500px;
  padding: 40px;
  background: #000;
  transition: transform .3s ease-out;
}

h1 {
  text-align: center;
}

.tile>* {
  color: white;
  transition: transform .3s ease-out;
}

.tile>.button {
  position: absolute;
  right: 0;
  top: 0;
  background: red;
  padding: 10px 15px;
  color: white;
  transform-origin: 100% 0;
}

.tile:hover {
  transform: scale(.9);
}

.tile:hover>* {
  transform: scale(1.1);
}
<div class="tile">
  <section>
    <h1>Hello World</h1>
    <p>I have an element that requires the background to be scaled, without scaling the elements within the parent. I have achieved this by using a pseudo element to define the background, and then on hover I simply scale the pseudo element. So far, so good...
      The problem is, I need some of the elements to stay inline with the scaled background, despite not scaling themselves. My original plan was to simply translate them, but I quickly realised that is not possible due to scale being based on multiples,
      and translate being based on percentage/pixels etc... The obvious solution is to scrap scale and instead use margin to shrink the absolutely positioned pseudo element. However, my reservation with this is that it is bad practice to transition the
      margin value. Can anybody think of a way in which I can use scale, and also maintain the alignment?</p>
  </section>
  <div class="button">Align Me</div>
</div>

另一个想法是为top的{​​{1}}和right设置动画:

.button
html,
body {
  width: 75%; 
  margin: 0;
  padding: 0
}

* {
  box-sizing: border-box
}

.tile {
  position: relative;
  width: 100%;
  padding: 40px;
  color: white;
}

.tile:hover:before {
  transform: scale(.9);
}

.tile:before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #000;
  z-index: -1;
  transition: transform .3s ease-out;
}

h1 {
  text-align: center;
}

.tile>.button {
  position: absolute;
  right: 0;
  top: 0;
  background: red;
  padding: 10px 15px;
  color: white;
  transition: .3s ease-out;
}

.tile:hover>.button {
  top: 5%;
  right: 5%
}

下一个想法是使用更复杂的代码,但仅对<div class="tile"> <h1>Hello World</h1> <p>I have an element that requires the background to be scaled, without scaling the elements within the parent. I have achieved this by using a pseudo element to define the background, and then on hover I simply scale the pseudo element. So far, so good... The problem is, I need some of the elements to stay inline with the scaled background, despite not scaling themselves. My original plan was to simply translate them, but I quickly realised that is not possible due to scale being based on multiples, and translate being based on percentage/pixels etc... The obvious solution is to scrap scale and instead use margin to shrink the absolutely positioned pseudo element. However, my reservation with this is that it is bad practice to transition the margin value. Can anybody think of a way in which I can use scale, and also maintain the alignment?</p> <div class="button">Align Me</div> </div>属性进行动画处理:

transform
html,
body {
  width: 75%;
}

* {
  box-sizing: border-box
}

.tile {
  position: relative;
  width: 100%;
  padding: 40px;
  color: white;
}

.tile:hover:before {
  transform: scale(.9);
}

.tile:before,
.tile>.button {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  width:100%; height:100%;  
  background: #000;
  transition: transform .3s ease-out;
}

h1 {
  text-align: center;
}

.tile>.button {
  z-index: 1;
  display: flex;
  align-items: flex-start;
  margin: 0 -100% -100% 0;
  background: transparent;
  transition: .3s ease-out;
  pointer-events: none;
}

.tile>.button div {
  padding: 10px 15px;
  background: red;
  cursor: pointer;
  pointer-events: all;
}

.tile>.button:before {
  content: '';
  flex: 1 0;
}

.tile:hover>.button {
  transform: translate3d(-5%, 5%, 0);
}