Search code examples
cssbox-shadow

Putting an "irregular" box shadow on a heading in CSS 3


I have an h2 heading with a background image as seen bellow:

body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
}

.title {
    font-size: 18px;
    padding: 10px 4px 20px 4px;
    margin: 0 0 10px;
    background: url('https://i.sstatic.net/yco0r.png') center bottom no-repeat;
}
<h2 class="title">Lorem ipsum</h2>

Since the website is responsive, the image would have to stretch or contract. So I would rather replace it with a purely CSS box-shadow.

I managed to obtain the effect below:

body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
}

p {
  line-height: 1.6;
  font-size: 13px;
  margin: 0 0 10px 0;
}

.section_title {
  font-size: 18px;
  margin: 0 0 10px 0;
  padding: 20px;
  text-align: center;
  box-shadow: 0 8px 4px -4px rgba(0, 0, 0, .3);
}
<div class="content_section">
  <h2 class="section_title">About us</h2>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veniam, odit.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi quod repudiandae cupiditate reprehenderit, error aspernatur labore cumque. Optio natus dolores molestiae molestias non totam corrupti.</p>
</div>

But unfortunately, it has a regular form, instead of "taller" in the middle, like the one I used an image for.

What am I missing?


Solution

  • Use a pseudo-element to achieve this effect, using border-radius:

    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
    }
    
    p {
      line-height: 1.6;
      font-size: 13px;
      margin: 0 0 10px 0;
    }
    
    .section_title {
      position: relative;
      font-size: 18px;
      margin: 0 0 10px 0;
      padding: 20px;
      text-align: center;
    }
    
    .section_title::before {
      content: '';
      position: absolute;
      left: 0;
      top: calc(100% - 12px);
      width: 100%;
      height: 8px;
      border-radius: 50%;
      box-shadow: 0 8px 4px -3px rgba(0, 0, 0, .3);
    }
    
    .section_title::after {
      content: '';
      position: absolute;
      left: 0;
      bottom: 0;
      width: 100%;
      height: 8px;
      background-color: #ffffff;
    }
    <div class="content_section">
      <h2 class="section_title">About us</h2>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Veniam, odit.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi quod repudiandae cupiditate reprehenderit, error aspernatur labore cumque. Optio natus dolores molestiae molestias non totam corrupti.</p>
    </div>

    Drawbacks: You must define a background-color on the ::after pseudo-element to the same as your background, in order to cover the top part of the shadow. You could try using clip and forget the ::after element but it doesn't have full cross-browser support. Also the values are hard-coded, you could adjust with percentages and rem/em (as box-shadow doesn't support percentage length values).