Vin*_*rma 5 html javascript css reactjs redux
我正在使用 CRA 创建的 React 应用程序中显示图像。每次我重新加载网页时,图像都会奇怪地闪烁,如下所示。
\n样式.css:
\nimg {\n width: 200px;\n height: 300px;\n object-fit: cover;\n}\nRun Code Online (Sandbox Code Playgroud)\n应用程序.tsx
\nimport React from \'react\';\nimport foo from \'./foo.jpg\';\n\nimport \'./styles.css\';\n\nconst App = () => <img src={foo} alt="foo" />;\n\nexport default App;\nRun Code Online (Sandbox Code Playgroud)\n包.json
\n{\n "name": "xyz",\n "version": "0.1.0",\n "private": true,\n "dependencies": {\n "@testing-library/jest-dom": "^4.2.4",\n "@testing-library/react": "^9.5.0",\n "@testing-library/user-event": "^7.2.1",\n "react": "^16.13.1",\n "react-dom": "^16.13.1",\n "react-scripts": "3.4.3"\n },\n "scripts": {\n "start": "react-scripts start",\n "build": "react-scripts build",\n "test": "react-scripts test",\n "eject": "react-scripts eject"\n },\n "eslintConfig": {\n "extends": "react-app"\n },\n "browserslist": {\n "production": [\n ">0.2%",\n "not dead",\n "not op_mini all"\n ],\n "development": [\n "last 1 chrome version",\n "last 1 firefox version",\n "last 1 safari version"\n ]\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n笔记:
\nobject-fit: cover;,但这是为了防止图像像初始图像一样奇怪地拉伸/收缩所必需的。object-fit: cover属性最初不会\xe2\x80\x99 应用于图像,并且需要几毫秒才能启动。law*_*itt 11
Having messed around with this for a good while now, I am pretty much convinced that it is a performance bug with Chromium browsers. Specifically, it seems related to the caching of images, and the optimizations that the browser makes when loading images into an img container with explicit height and width dimensions.
I say this because in my tests, emptying the cache before a reload will make the browser apply object-fit before the first paint happens. I also noticed that regardless of object-fit being present, cached images will be loaded into an img container with defined height and width a split second before img containers with only one or neither of these dimensions. This appears to be where the bug is occuring. The object-fit rule is only being applied during the second paint layer.
Maybe you can try and reproduce this with the following snippet to confirm? I've used a random placeholder image here but you might want to use a local image. If anyone can provide a more detailed explanation I'd be interested to hear it. As mentioned in the comments, this is reproducible with only HTML/CSS and network throttling, although I have found the effect to be much more pronounced in a React context:
const { Fragment } = React;
const App = () => {
return (
<Fragment>
<p>Object fit with two explicit dimensions</p>
<img src="https://source.unsplash.com/RN6ts8IZ4_0/600x400" className="img-fit"></img>
<p>Positioned element with one explicit dimension</p>
<div className="container">
<img src="https://source.unsplash.com/RN6ts8IZ4_0/600x400" className="img-position"></img>
</div>
</Fragment>
);
};
ReactDOM.render(<App/>, document.body);Run Code Online (Sandbox Code Playgroud)
.img-fit {
width: 200px;
height: 300px;
object-fit: cover;
}
.container {
width: 200px;
height: 300px;
overflow: hidden;
position: relative;
}
.img-position {
height: 100%;
position: absolute;
left: 50%;
transform: translateX(-50%);
}Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>Run Code Online (Sandbox Code Playgroud)
Regardless, the second image in the snippet above is one possible workaround for this issue if it continues to give you grief. You choose the dimension you want to scale to on the parent container by making the img either 100% height or width. It can then be centred (or otherwise adjusted) with a combination of directional offset and transform. This is obviously not as dynamic as object-fit because you have to decide beforehand how to scale the image to get either a cover or contain effect.
Some alternative solutions include:
1. Use a background image instead
我发现最终派生的backgroundCSS 属性object-fit不会遇到同样的错误。使用 adiv代替img标签并将图像放在其背景上:
div {
width: 200px;
height: 300px;
background: url('path/yourimg.jpg') center / cover;
}
Run Code Online (Sandbox Code Playgroud)
2. 预加载(HTML)
我发现的另一个修复是预加载图像,这向浏览器发出信号,表明它是关键资源,应该立即获取。这似乎支持了这样的观点:问题最终归结于浏览器优化。
不幸的是,这并不真正符合 React 标准,因为你只有一个 HTML 页面,并且它很容易被这些链接填满,但无论如何它都能工作。把这个放在head:
<link rel="preload" href="path/yourimage.jpg" as="image"/>
Run Code Online (Sandbox Code Playgroud)
3.预加载(React)
您可以在 React 中模拟预加载,方法是等待图像的onload事件触发,然后再使其对用户可见。这可能与在 JSX 中使用相关类的单行代码一样快速且肮脏:
// app.js
const App = () => <img src={foo} onLoad={e => e.target.classList.add('visible')}/>;
// index.css
img {
width: 200px;
height: 300px;
object-fit: cover;
visibility: hidden;
}
.visible {
visibility: visible;
};
Run Code Online (Sandbox Code Playgroud)
或者,如果您正在加载一批图像,您可以等待它们全部加载完毕,然后再显示组件/批次本身。这带来了一些潜在的布局变化的缺点,并且可能需要一些优化来处理大批量,但你明白了:
import foo from 'path/foo.jpg';
import bar from 'path/bar.jpg';
const App = () => {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
const loadArray = [foo, bar].map(src => {
return new Promise((res, rej) => {
const img = new Image();
img.src = src;
img.onload = () => res();
img.onerror = () => rej();
})
});
Promise.allSettled(loadArray).then(() => setLoaded(true));
}, []);
return loaded && (
<>
<img src={foo} alt="foo"></img>
<img src={bar} alt="bar"></img>
</>
);
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2585 次 |
| 最近记录: |