skip to Main Content

I’m trying to recreate Google Maps’s icon (2020). The colorful background and the donut hole are easy enough: I just need some gradients and a mask.

Here’s a snippet that shows my current efforts (and a codepen, if you want to play with it):

:root {
  --1-3: calc(100% / 3);
  --2-3: calc(100% / 3 * 2);
  --sqrt-2: 1.4142135624;
  
  --hole-diameter: calc(100% / var(--sqrt-2) / 3);
  
  --red: #ea4335;
  --yellow: #fbbc04;
  --green: #34a853;
  --blue: #1a73e8;
  --azure: #4285f4;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
}

#wrapper {
  margin: 3em auto;
  width: 10em;
  background: linear-gradient(90deg, #c0392b, #8e44ad);
}

#icon {
  --mask: radial-gradient(
    circle at center,
    transparent calc(var(--hole-diameter) - 1px),
    #000 calc(var(--hole-diameter) + 1px)
  );
  
  border-radius: 50% 50% 50% 0;
  aspect-ratio: 1 / 1;
  background:
    linear-gradient(
      180deg,
      var(--red) var(--1-3),
      var(--yellow) var(--1-3) var(--2-3),
      var(--green) var(--2-3)
    ),
    linear-gradient(
      180deg,
      var(--blue) var(--1-3),
      var(--azure) var(--1-3) var(--2-3),
      var(--green) var(--2-3)
    ) calc(100% - 1px);
  background-size: 50% 100%;
  background-repeat: no-repeat;
  -webkit-mask: var(--mask);
  mask: var(--mask);
  rotate: -45deg;
}
<div id="wrapper">
  <div id="icon"></div>
</div>

However, I can’t wrap my head around its peculiar shape. Is it possible to create such a shape with CSS only?

It should be obvious that I’m not looking for an SVG-based solution. I’m doing this as a pet project, so I just need something that works in at least one browser.

2

Answers


  1. Here’s the best I could come up with, by abusing multiple radial-gradient, -webkit-mask-image, -webkit-mask-image-composite and, unfortunately: a sibling-element for the "pointy-bit" instead of being able to extend the original #icon, nor use an ::after element (as the ::after element will be clipped by the mask of its parent).

    (I suppose this could be re-organized to make the circular part at the top use ::before and the pointy-bit use ::after and otherwise have #icon serve only as a container and bounds for its two psedoelement children, but that’s an exercise left for the reader).

    This is how it looks in Chrome. I haven’t tested in any other browsers:

    enter image description here


    :root {
        --1-3: calc(30%);
      --2-3: calc(70%);
        --sqrt-2: 1.41421356237;
        --inner-radius: calc(18.4%);
    
        --red: #ea4335;
        --yellow: #fbbc04;
        --green: #34a853;
        --blue: #1a73e8;
        --azure: #4285f4;
    }
    
    * {
        box-sizing: border-box;
    }
    
    body {
        margin: 0;
    }
    
    #wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 2em;
        margin: 1em;
    }
    
    #wrapper > div {
        border-radius: 1em;
        background: linear-gradient(90deg, #c0392b, #8e44ad);
      overflow: hidden;
    }
    #wrapper > div > h2 {
      font-family: sans-serif;
        text-align: center;
      background-color: white;
      border-radius: 0.25em;
      width: 90%;
      margin-left: auto;
      margin-right: auto;
    }
    
    #image > img {
      transform-origin: 50% 35%;
      /*transform: rotate(50deg);*/
    }
    
    #icon {
        aspect-ratio: 1 / 1;
      background-image:
            linear-gradient(
                180deg,
                var(--red) var(--1-3),
                var(--yellow) var(--1-3) var(--2-3),
                var(--green) var(--2-3)
            ),
            linear-gradient(
                180deg,
                var(--blue) var(--1-3),
                var(--azure) var(--1-3) var(--2-3),
                var(--green) var(--2-3)
            );
        
        background-position-x: 0, calc(100% - 1px);
        background-position-y: 0, 0;
        
        background-size: 50% 100%;
        background-repeat: no-repeat;
    
        -webkit-mask-image:
        /* The radius of the circle at 100% is actually the corners of the bounding rect, not the perpendicular top+bottom/side edges, hence the weird numbers. */
        radial-gradient(
          circle at center,
          transparent 28.2%,
          black       calc(28.2% + 1px),
          black       70%,
          transparent calc(70.0% + 1px)
        );
        
        rotate: -50deg;
      
      z-index: 10;
    }
    
    #tip {
      aspect-ratio: 26 / 25;
      width: 100%;
      background-color: #47A756;
      margin-top: -14.2%; * this is relative to the #tip element's *width* btw. */
      z-index: 5;
      background-image:
        linear-gradient(
          130deg,
          var(--yellow) 0% 25.5%,
          var(--green) 25.5%
        );
      
      background-size: cover;
      background-repeat: no-repeat;
    
      -webkit-mask-repeat: no-repeat;
      -webkit-mask-image:
        radial-gradient( ellipse 127.3% 100% at -85.62% 60.5%, transparent 0%, transparent 100%, black 100% ),
        radial-gradient( ellipse 127.3% 100% at 185.62% 60.5%, transparent 0%, transparent 100%, black 100% ),
        linear-gradient( to bottom, black 55%, transparent 50% ),
        radial-gradient( ellipse 8.4% 8.8% at 50% 55%, black 100%, transparent 100% );
    
    /* https://tympanus.net/codrops/css_reference/mask-composite/ */
      -webkit-mask-composite:
        source-in,
        source-in,
        source-over;
    }
    <div id="wrapper">
        
      <div id="image">
        <h2>Google Maps Logo SVG</h2>
        <img src="https://upload.wikimedia.org/wikipedia/commons/a/aa/Google_Maps_icon_(2020).svg" alt="Google Maps icon"/>
        </div>
        
      <div id="attempt">
        <h2>Image-Mask Abuse</h2>
        <div id="icon"></div>
        <div id="tip"></div>
        
      </div>
    </div>
    Login or Signup to reply.
  2. An approximation with one element that should work in all the browsers:

    .logo {
      width: 200px; /* control the size */
      aspect-ratio: .7;
      background:
       linear-gradient(130deg,#0000 53%,#34a853 53.5%),
       conic-gradient(from 40deg at 36% 26%, #4285f4 25%,#fbbc04 0 50%,#ea4335 0 75%, #1a73e8 0);
      -webkit-mask:
        radial-gradient(#000 69%,#0000 71%) 
         bottom/10% 9% no-repeat,
        radial-gradient(92% 173% at 100% 116%,#0000 98%,#000) 
         100% 97%/50% 18% no-repeat,
        radial-gradient(92% 173% at 0%   116%,#0000 98%,#000) 
         0%   97%/50% 18% no-repeat,
        conic-gradient(from -35deg at 50% 90%,#000 70deg,#0000 0)
         bottom/100% 43% no-repeat,
        radial-gradient(#0000 27%,#000 28% 70%,#0000 71%)
         top   /100% 70% no-repeat;
      
      display: inline-block;
    }
    
    html {
      min-height: 100%;
      background: repeating-linear-gradient(-45deg, #fff 0 20px, #f9f9f9 0 40px);
      text-align: center;
    }
    <div class="logo"></div>
    
    <img src="https://upload.wikimedia.org/wikipedia/commons/a/aa/Google_Maps_icon_(2020).svg" width="200">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search