英文:
How to change background images based on screen-size in HTML/CSS/Javascript? (art direction)
问题
我目前正在进行一个项目,其中有一些元素在桌面上以5:6的宽高比显示为卡片。在移动设备上,相同的元素以样式化列表的条目形式显示,其宽高比为1:10。
为了适应这种情况,每个元素目前被拆分为两个版本 - 一个桌面版本和一个移动版本。我目前正在尝试合并这两个版本,为将来的代码更改打下基础,并在添加新元素时减少维护时间。以下是当前代码的摘录(实际上已经有超过15个卡片了,在这里查看扩展版本和CSS):
<div class="desktop-wrapper">
<div class="card" style="background-image: url('[name]-l.webp')">
<div class="card-flexbox">
<h2 class="titel">Example 1</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="card-btn">More info</a>
</div>
<!--some overlays for aesthetics-->
<div class="img-overlay-2"></div>
<div class="img-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
(...)
</div>
<!--mobile version-->
<div class="mobile-wrapper">
<a href="#" class="mobile-card-link">
<div class="mobile-karte" style="background-image: url('[name]-s.webp')">
<h3 class="titel">Example 1</h3>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="(...)"></path></svg>
<!--overlay for aesthetics-->
<div class="mobile-card-overlay"></div>
</div>
</a>
(...)
</div>
问题:每个版本的卡片使用不同的图片,出于美观的原因。移动版本使用宽图 "[name]-s.webp",而桌面版本使用较高的图 "[name]-l.webp"。
我希望解决这个问题的方法是编写一个脚本,利用上述命名约定。理想情况下,我只需在HTML中编写 <div class="mobile-karte" style="background-image: url('./img/stamp')">...</div>
,然后脚本根据屏幕大小扩展背景图像的URL - 例如,在600px的断点以下将 "-s.webp" 添加到背景图像的URL中。我想的是类似于这个,只是更自动化一些。
这种方法可行吗?如果可以,怎么做?
我考虑的其他选项:
- 为每个元素分配一个独立的ID,并创建媒体查询来在特定断点更换背景图像。这是一个不错的备选方案,但我更希望有一个脚本来简化事情并减少手动工作。
- 使用 image-set()。每次添加新卡片时似乎需要大量手动工作。而且,据我所知,它不允许使用特定的断点。
- 使用 srcset。虽然它允许使用特定的断点,但我必须将背景图像创建为 img 元素,这似乎有点复杂。
英文:
I'm currently working on a project in which I have elements that are displayed as cards with an aspect-ratio of 5:6 on desktop. On mobile, the same elements are displayed as entries of a stylized list that are very different with a aspect-ratio 1:10.
To accommodate for this situation, each element is currently split in two – one desktop version, and one mobile version. I'm currently trying to merge both versions to lay groundworks for future code changes, and to reduce maintenance time when adding new elements. This is an excerpt of the current code (in actuality there are more than 15 cards already, see the extended version and CSS here):
<div class="desktop-wrapper">
<div class="card" style="background-image: url('[name]-l.webp')">
<div class="card-flexbox">
<h2 class="titel">Example 1</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="card-btn">More info</a>
</div>
<!--some overlays for aesthetics-->
<div class="img-overlay-2"></div>
<div class="img-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
(...)
</div>
<!--mobile version-->
<div class="mobile-wrapper">
<a href="#" class="mobile-card-link">
<div class="mobile-karte" style="background-image: url('[name]-s.webp')">
<h3 class="titel">Example 1</h3>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="(...)" /></svg>
<!--overlay for aesthetics-->
<div class="mobile-card-overlay"></div>
</div>
</a>
(...)
</div>
The problem: Each version of the cards uses a different picture for art direction reasons. A wide version "[name]-s.webp" is used for the mobile version, and a taller version for desktop, "[name]-l.webp".
My preferred way of solving the issue would be having a script that takes advantage of the above mentioned naming convention. Ideally I'd just write <div class="mobile-karte" style="background-image: url('./img/stamp')">...</div>
in my HTML and have the script extend the background-image url based on screen size — for example by adding "-s.webp" to the background-image url below a breakpoint of 600px. I'm thinking of something like this, just more automated.
Is this possible? If so, how?
Other options I thought about:
- Giving each element an individual ID and creating media queries to change out the background-image at a certain breakpoint. A good fallback-option, but I'd prefer a script to simplify things and reduce manual labour.
- Using image-set(). Seems like a lot of manual labour each time a new card has to be added. Also, it doesn't allow for specific breakpoints to the best of my knowledge.
- srcset. While it would allow for specific breakpoints, I'd have to create my background-images as img-elements, which seems a bit complicated.
答案1
得分: 1
老实说,我认为你不需要任何JS代码来处理你的问题,只需要更好地管理媒体查询。
我在CodePen上创建了一个可行的解决方案,在这里
基本上,我完全删除了移动部分。
<div class="wrapper">
<div class="karte">
<div class="karte-flexbox">
<h2 class="titel">
Example 1
</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="karte-btn">
More info
</a>
<svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
</svg>
</div>
<div class="bild-overlay-2"></div>
<div class="bild-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
<div class="karte">
<div class="karte-flexbox">
<h2 class="titel">
Example 2
</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="karte-btn">
More info
</a>
<svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
</svg>
</div>
<div class="bild-overlay-2"></div>
<div class="bild-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
</div>
然后,我将所有的:hover
交互放在了媒体查询内部,因为它们只用于桌面版本。
@media (min-width: 600px){
/* hover effects are useful only in desktop mode */
.karte:hover {
box-shadow: 4px 4px 7px 1px rgba(0, 0, 0, 0.2);
left: -2px;
top: -2px;
}
.karte:hover .bild-overlay-2 {
opacity: 1;
}
.karte:hover .karte-flexbox {
top: 0%;
opacity: 1;
}
.karte:hover .titel {
margin: 0;
font-size: 22px;
}
.karte:hover .hover-text,
.karte:hover .karte-flexbox .karte-btn {
opacity: 1;
}
.karte-btn:hover {
background: #fff;
/* border: 2px solid #b4eb14; */
color: #b4eb14;
}
.mobile-icon {
display: none;
}
}
之后,在媒体查询内部,我修改了已经存在的部分,以正确适应移动视图:
@media (max-width: 600px) {
.wrapper {
flex-direction: column;
}
.karte {
width: 100%;
background-image: url('https://i.ibb.co/PCZRF9m/stamp-s.webp');
height: 60px;
border-radius: 10px;
}
.karte-btn, .hover-text {
display: none;
}
.titel{
font-weight: normal;
}
.karte-flexbox{
position: relative;
top: 0px;
left: 0px;
padding: 0px 10px;
width: 90%;
height: 100%;
flex-direction: row;
font-weight: 400;
}
.bild-overlay-2{
opacity: 1;
background: linear-gradient(
90deg,
rgba(0, 110, 145, 0.8) 42%,
rgba(0, 0, 0, 0) 100%
);
}
}
移动媒体查询的最重要部分:
- 包装器获得了
flex-direction: row
以处理新的方向 - .karte更改了背景图像和尺寸
- .karte-flexbox现在相对于父元素定位,因为我们不再需要对其进行动画处理
- 我们重用.bild-overlay-2来给出相同的线性渐变,只是将其旋转了90度而不是180度
还有一些其他的小改动,比如SVG只在移动视图中可见。
这个CodePen是可用的,并且几乎与你的结果完全相同,但只使用了每个卡片的一个版本。
英文:
To be honest, I don't think you need any JS code to handle your problem. Just better media-query management.
I created a codepen with a working solution, here
Basically, I entirely removed the mobile section.
<div class="wrapper">
<div class="karte">
<div class="karte-flexbox">
<h2 class="titel">
Example 1
</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="karte-btn">
More info
</a>
<svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
</svg>
</div>
<div class="bild-overlay-2"></div>
<div class="bild-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
<div class="karte">
<div class="karte-flexbox">
<h2 class="titel">
Example 2
</h2>
<p class="hover-text">
Lorem ipsum dolor sit amet, consectetur adipisici elit
</p>
<a href="#" class="karte-btn">
More info
</a>
<svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
<path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
</svg>
</div>
<div class="bild-overlay-2"></div>
<div class="bild-overlay-1"></div>
<!--this link makes everything clickable-->
<a href="#">
<span class="link-span"></span>
</a>
</div>
</div>
Then, I moved all the :hover
interactions inside a media query, since they are used only for the desktop version.
@media (min-width: 600px){
/* hover effects are useful only in desktop mode */
.karte:hover {
box-shadow: 4px 4px 7px 1px rgba(0, 0, 0, 0.2);
left: -2px;
top: -2px;
}
.karte:hover .bild-overlay-2 {
opacity: 1;
}
.karte:hover .karte-flexbox {
top: 0%;
opacity: 1;
}
.karte:hover .titel {
margin: 0;
font-size: 22px;
}
.karte:hover .hover-text,
.karte:hover .karte-flexbox .karte-btn {
opacity: 1;
}
.karte-btn:hover {
background: #fff;
/* border: 2px solid #b4eb14; */
color: #b4eb14;
}
.mobile-icon {
display: none;
}
}
After that, inside a media query, I modified the already present sections to fit correctly inside the mobile view:
@media (max-width: 600px) {
.wrapper {
flex-direction: column;
}
.karte {
width: 100%;
background-image: url('https://i.ibb.co/PCZRF9m/stamp-s.webp');
height: 60px;
border-radius: 10px;
}
.karte-btn, .hover-text {
display: none;
}
.titel{
font-weight: normal;
}
.karte-flexbox{
position: relative;
top: 0px;
left: 0px;
padding: 0px 10px;
width: 90%;
height: 100%;
flex-direction: row;
font-weight: 400;
}
.bild-overlay-2{
opacity: 1;
background: linear-gradient(
90deg,
rgba(0, 110, 145, 0.8) 42%,
rgba(0, 0, 0, 0) 100%
);
}
}
Most important parts for the mobile media queries:
- the wrapper gets a
flex-direction: row
to handle the new orientation - the .kart changes the background image and its dimentions
- the .karte-flexbox is now positioned relative to the parent, since we don't need to animate it animore
- we reuse the .bild-overlay-2 to give the same linear gradient, just rotated of 90deg instead of 180deg
The are also some others small changes as the SVG being visible only in the mobile view.
The codepen is usable and gets a result nearly identical to yours, but using only one version of each card
答案2
得分: 1
我最终自己找到了解决方案。使用data-name属性为卡片设置背景图像(甚至链接),然后使用一个小脚本自动生成相应的背景图像。代码如下所示:
<div class="card" data-name="example-1">
<div class="flexbox">
<a href="#" class="card-btn">
More info
</a>
</div>
</div>
<script>
const cardElements = document.querySelectorAll('.card');
function updateBackgroundImage(cardElement) {
const name = cardElement.getAttribute('data-name');
const imageUrl = window.innerWidth > 600 ? `/assets/img/${name}-l.webp` : `/assets/img/${name}-s.webp`;
cardElement.style.backgroundImage = `url('${imageUrl}')`;
}
function updateCardLinks(cardElement) {
const name = cardElement.getAttribute('data-name');
const links = cardElement.querySelectorAll('a');
links.forEach(link => {
link.href = `https://www.example.com/${name}/`;
});
}
cardElements.forEach(cardElement => {
updateCardLinks(cardElement);
updateBackgroundImage(cardElement);
window.addEventListener('resize', () => {
updateBackgroundImage(cardElement);
});
});
</script>
请注意,这只是一个示例代码,具体实现可能需要根据你的需求进行调整。
英文:
I ended up finding a solution on my own. Using data-name attributes for the cards and then having a small script generate the according background-images (and even links) automatically.
It looks something like this:
<div class="card" data-name="example-1">
<div class="flexbox">
<a href="#" class="card-btn">
More info
</a>
</div>
</div>
<script>
const cardElements = document.querySelectorAll('.card');
function updateBackgroundImage(cardElement) {
const name = cardElement.getAttribute('data-name');
const imageUrl = window.innerWidth > 600 ? `/assets/img/${name}-l.webp` : `/assets/img/${name}-s.webp`;
cardElement.style.backgroundImage = `url('${imageUrl}')`;
}
function updateCardLinks(cardElement) {
const name = cardElement.getAttribute('data-name');
const links = cardElement.querySelectorAll('a');
links.forEach(link => {
link.href = `https://www.example.com/${name}/`;
});
}
cardElements.forEach(cardElement => {
updateCardLinks(cardElement);
updateBackgroundImage(cardElement);
window.addEventListener('resize', () => {
updateBackgroundImage(cardElement);
});
});
</script>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论