'How to position a background on one side of centered content while making the BG translucent without distortion?

I'm working on the following layout issue: the page heading is center aligned. It should have a background image on its left side, and the background should also be made semi-transparent. The heading content may be of various lengths; the positioning of the background needs to take this into account. The layout should be the same on both desktop and mobile. For example:

logo behind text

So far, I've been able to make the background image semitransparent and center it by using the ::after pseudo-element. The image is set as the background of the ::after, and justification on the parent also positions the background. Code so far:

.heading-bg-logo {
    display: flex;
    justify-content: center;
    color: blue;
}

.heading-bg-logo::after {
    content: "";
    display: inline-block;
    width: 1em;
    height: 1em;
    background: url(https://images.unsplash.com/photo-1581079289196-67865ea83118?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=120&q=80);
    background-repeat: no-repeat;
    background-size: 100%;
    position: absolute;

    z-index: -1;
    opacity: 0.2;
}
<h2 class="heading-bg-logo">
   Test Heading
</h2>
  • The issue at this point is that the logo positioned in the center behind the heading, rather than the left side of the heading text. How can I position it on the left side of the content?
  • Second Issue which i have is that the Logo Size should be customizable.

Note: I've used a demo image here from Unsplash.



Solution 1:[1]

Background sizing and positioning by themselves shouldn't require more than background properties on the element itself. As long as you can get the content box to shrink to fit the content, background-origin can be used to position the background relative to the content box (or the padding box, if you want the background to extend beyond the content box). However, requiring additional transparency on the background steers this towards a pseudo-element.

An alternative to a pseudo-element that can be used in certain circumstances is to use an inset box-shadow with a partially transparent color to wash-out the image. This only works if the background image is on top of a solid color; the same color is then used as the box-shadow color. Note the transparency of the box-shadow is the inverse of the transparency for the image: the more "transparent" the background is supposed to be, the less transparent the box-shadow color.

The other tricky aspect is in how you shrinkwrap the content. The simplest is to use a width of fit-content, though it's not supported in older browsers:

.heading-bg-logo {
color: blue;
width: fit-content;
margin: auto;
padding: 0 0.5em;

/* The spread-radius needs to be large enough to cover the background */
box-shadow: 0 0 0 1000px inset rgba(255, 255, 255, 0.8);
background: url("https://images.unsplash.com/photo-1581079289196-67865ea83118?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3269&q=80");
background-origin: padding-box;
background-repeat: no-repeat;
background-size: contain;
}
<span>content before</span>
<h2 class="heading-bg-logo">Test Heading</h2>
<span>content after</span>

Note that a content-size of contain is used with the sample image to scale it to fit within the element without distorting the aspect ratio.

If using a pseudo-element to achieve semitransparency, then you can position it relative to the content using the usual approach: relatively position the parent element and absolutely position the pseudo-element:

.heading-bg-logo {
color: blue;
width: fit-content;
margin: auto;
position: relative;
}

.heading-bg-logo::after {
content: " ";
opacity: 0.2;
background: url("https://images.unsplash.com/photo-1581079289196-67865ea83118?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3269&q=80");
background-repeat: no-repeat;
background-size: contain;
position: absolute;
top: 0;
left: -0.5em;
height: 100%;
width: 100%;
z-index: -1;
}
<span>content before</span>
<h2 class="heading-bg-logo">Test Heading</h2>
<span>content after</span>

Solution 2:[2]

Fast fix. Add margin-right: 150px; to your .heading-bg-logo::after class.

Update (responsive behavior)

.c {
  display: flex;
  justify-content: center;
  align-items: center;   
}
.c h2 {
  color: blue;  
}

.heading-bg-logo {  
  position: relative;
}

.heading-bg-logo::after {     
  position: absolute;
  top:-20px;
  content: "";
  margin-left: -80px;  
  width: 120px;
  height: 40px;  
  background: url(https://images.unsplash.com/photo-1581079289196-67865ea83118?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3269&q=80);
  background-repeat: no-repeat;
  background-size: 100% 95%;  
  z-index: -1;
  opacity: 0.2;
}
<div class="c">
  <div class="heading-bg-logo"></div>
  <div>
    <h2>Test Heading Test Heading</h2>  
  </div>
</div>

<div class="c">
  <div class="heading-bg-logo"></div>
  <h2>Test Heading </h2>  
</div>

.heading-bg-logo {
    display: flex;
    justify-content: center;
    color: blue;
}
.heading-bg-logo::after {
   
        content: "";
    display: inline-block;
    width: 120px;
    height: 40px;
  margin-right: 150px;
    background: url(https://images.unsplash.com/photo-1581079289196-67865ea83118?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3269&q=80);
    background-repeat: no-repeat;
    background-size: 100% 95%;
    position: absolute;

    z-index: -1;
    opacity: 0.2;
}
<h2 class="heading-bg-logo">
   Test Heading
</h2>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2