变换缩放保持了被缩放元素周围的原始空间。

39

我有两个嵌套的div。其中一个

transform: scale(0.5)

它们都是display: inline-block;

我需要发生的是,

外部
的宽度适应内部
的宽度。这就是我所期望的,但事实并非如此。发生的情况是,外部
“认为”内部
具有其原始大小。

仅当内部

使用比1小的缩放因子(例如:0.5)时才会使外部
的宽度适应内部的宽度,而不是transform: scale(1)

我需要一种CSS方式来优雅地实现这一点。

.red {
  background-color: #f00;
}

.green {
  background-color: #0f0;
}

.box_1,
.box_2 {
  display: inline-block;
}

.box_1 {
  width: 300px;
  height: 300px;
  transform: scale(0.5);
  transform-origin: left top;
}
<div class="box_2 green">
  <div class="box_1 red">Hello World</div>
</div>

有什么解决方法吗?

5个回答

16

一种残忍的方式是通过虚拟减少元素所需的空间。

您的示例显示已知宽度和高度,因此很容易。否则,您将需要使用JavaScript方法。

.box_1 {
    width:  300px;
    height: 300px;
    transform: scale(0.5);
    transform-origin: left top;
  margin-bottom:-150px;
  margin-right:-150px;
}

https://jsfiddle.net/0bc4sxk3/1/

扩大规模意味着正面的边缘。

转换只在屏幕上发生,元素仍然使用文档流中的初始空间和所需位置。


那种方法对我不起作用,因为我需要外部 div 的大小适应内部 div。换句话说:两者具有相同的大小。 - nightclub
@nightclub 如果你同时设置它们的大小,父级就没有办法缩小。你的fiddle少了这个 :( 我猜你误解了transform的工作方式。 - G-Cyrillus
我没有为外部div指定任何大小,因此我希望外部div可以收缩。 - nightclub
@nightclub 不会的,就像我在答案结尾写的那样。position:relative; + coordonates 只是将元素在屏幕上移动,而不是在布局中移动;)https://jsfiddle.net/0bc4sxk3/3/ 这与您使用 transform 遇到的类似问题,这是正常行为 :) - G-Cyrillus

11

我认为一个解决方案是将缩小的元素包装在一个具有overflow: hidden属性的元素中。

这个包装器应该具有缩小后内容的确切尺寸。

对于我来说,这个解决方案是最好的。

.wrapper {
  width: 150px;
  height: 150px;
  overflow: hidden;
}

.content {
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  height: 300px;
  transform: scale(0.5);
  transform-origin: left top;
}

.box_1,
.box_2 {
  display: inline-block;
}

.red {
  background-color: #f00;
}

.green {
  background-color: #0f0;
}
<div class="box_2 green">
  <div class="box_1 red">Hello World</div>
</div>


2
不错的解决方案!但是我认为 position: absolute 是不必要的。 - Shahriar
我将您的解决方案转换为片段演示,使用原始的HTML和样式。它是否按预期工作?请根据需要进行修订以进行演示。 - isherwood
这应该是被接受的答案。 - ashuvssut
好的解决方案!我遇到了完全相同的问题,而overflow: hidden;对我很有帮助。 - NULL

2
最初的回答:可以使用一个空的大小元素,并将其放置在被缩小元素的下方,使其具有与缩小元素相同的外部尺寸且不进行缩放。这样可以驱动父元素的大小,然后绝对定位缩小后的元素在大小元素的上方。

.red { background-color: #f00; }
.green { background-color: #0f0; }
.blue { background-color: #00f; }

.container {
 position: relative;
 display: inline-block;
}

.sizingBox {
  width: 150px;
  height: 150px;
}

.content {
  position: absolute;
  top: 0;
  left: 0;
 width: 300px;
 height: 300px;
 transform: scale(0.5);
 transform-origin: left top;
}
 <div class="container green">
      <div class="sizingBox blue"></div>
     <div class="content red">Hello World</div>
 </div>


2
如果有人正在寻找一个复制粘贴的React组件,这个似乎基于Guy的代码可以工作:
import * as React from "react";

interface Props
  extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
  scale?: number;
  style?: React.CSSProperties;
  fullHeight: number;
  fullWidth: number;
}

export const ScaleBox: React.FC<Props> = ({
  scale = 1,
  style,
  fullWidth,
  fullHeight,
  children,
  ...rest
}) => {
  return (
    <div
      data-comment={"ScaleBox Container"}
      style={{ position: "relative", display: "inline-block", ...style }}
      {...rest}
    >
      <div
        data-comment={"ScaleBox Sizing Box"}
        style={{ width: fullWidth * scale, height: fullHeight * scale }}
      ></div>
      <div
        data-comment={"ScaleBox Content"}
        style={{
          transform: `scale(${scale})`,
          transformOrigin: "top left",
          position: "absolute",
          top: 0,
          left: 0,
        }}
      >
        {children}
      </div>
    </div>
  );
};


1
React没有被标记在问题上。这个答案超出了范围。 - isherwood

2

后来,我在mikeysee的React组件基础上进行了改进,并编写了一个可以与动态大小的内容一起使用的组件(它使用负边距来避免调整子元素的内容大小):

import * as React from 'react';
import useResizeObserver from '@react-hook/resize-observer';

interface Props
    extends React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    > {
    scale?: number;
    style?: React.CSSProperties;
}

/**
 * The ScaleBox is an element that scales its content using CSS transform scale
 * and makes sure the flow around the box is as if the box had the size
 * according to the applied scale.
 *
 * The parent element of a ScaleBox must have the overflow: 'hidden' style.
 */
export const ScaleBox: React.FC<Props> = ({ scale = 1, style, children }) => {
    const [marginX, setMarginX] = React.useState('0px');
    const [marginY, setMarginY] = React.useState('0px');
    const divRef = React.useRef<HTMLDivElement>(null);

    useResizeObserver(divRef, (target) => {
        setMarginX(`${(scale - 1) * target.contentRect.width}px`);
        setMarginY(`${(scale - 1) * target.contentRect.height}px`);
    });

    React.useEffect(() => {
        if (divRef.current) {
            setMarginX(`${(scale - 1) * divRef.current.offsetWidth}px`);
            setMarginY(`${(scale - 1) * divRef.current.offsetHeight}px`);
        }
    }, [scale]);

    return (
        <div
            ref={divRef}
            style={{
                ...style,
                transform: `scale(${scale})`,
                transformOrigin: 'top left',
                marginRight: marginX,
                marginBottom: marginY
            }}
        >
            {children}
        </div>
    );
};

1
React没有被标记在问题上。这个答案超出了范围。 - isherwood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接