How to recreate 2020 Google Maps icon's shape without SVG?

272 Views Asked by At

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

There are 2 best solutions below

1
Temani Afif On BEST ANSWER

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">

3
Dai On

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>