CSS4 conic-gradient를 선점하는 방법

CSS3의 그라데이션에는 선형 그라데이션의 linear-gradient와 방사형 그라데이션의 radial-gradient가 있지만, CSS4의 Working Draft에는 원추형으로 그라데이션시키기 위한 conic-gradient라는 항목이 존재합니다. 다만, conic-gradient 는 아직 초안 단계이므로 2017/7 시점에서는 어느 브라우저에서도 사용할 수 없습니다.



이번 디자이너에게 상담되어 여러가지 조사해 본 결과 몇 가지 방법으로 conic-gradient 를 실현할 수 있었으므로 그 방법에 대해 소개하고 싶습니다.

conic-gradient를 실현하는 방법



내 쪽에서 조사한 한이라면 이하의 3개의 방법이 발견되었습니다.

  • CSS conic-gradient() polyfill 사용
  • CSS의 clip property를 사용해 표현한다 ( 샘플 )
  • SVG 마스킹을 사용하여 표현하기 ( 샘플 )

  • 1은 라이브러리 의존이 됩니다만, 간단&다기능이므로 실장 방침등으로 문제 없으면 제일 간편한 수단이라고 생각합니다.
    2는 JavaScript를 사용하지 않고 CSS만으로 표현할 수 있으므로 비교적 성능이 우수할 수 있지만, clip 프로퍼티 의존이므로 IE라면 제대로 동작하지 않습니다.
    이번에, 나는 3의 방법으로 실장해 보았다 ( 그러나 ) 때문에, 그 실장 방법과 구조에 대해 해설합니다.

    SVG 마스킹을 사용하여 표현하는 방법


    conic-gradient 를 의사적으로 표현하는 순서는 대략 말하면 다음과 같습니다. 각 항의 상세에 대해서는 후술한다.
  • 원형으로 그라데이션이 적용된 마스킹 요소를 생성합니다
  • 도형에 마스킹 적용
  • 마스킹 된 도형을 겹칩니다

  • 절차의 상세를 설명하기 전에 억제해 두고 싶은 일로서 SVG의 마스킹에 대해서 간단하게 소개해 둡니다.

    SVG의 마스킹이란?



    SVG의 마스킹을 사용하면 명도의 정도에 따라 요소를 부분적으로 투과시킬 수 있습니다. 밝기가 낮을수록(검정색에 가까울 수 있음) 투명하고 밝기가 높을수록(흰색에 가까울) 불투명해집니다.
    다음 코드는 빨간색 rect 요소에 마스크를 적용하여 그라데이션으로 투과시키는 예제입니다.

    HTML
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
        <linearGradient id="Gradient">
          <stop offset="0" stop-color="white" stop-opacity="0" />
          <stop offset="1" stop-color="white" stop-opacity="1" />
        </linearGradient>
        <mask id="Mask">
          <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)"  />
        </mask>
      </defs>
    
      <rect x="0" y="0" width="200" height="200" fill="green" />
      <rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" />
    </svg>
    



    참고 : 클리핑 및 마스킹 - SVG | MDN

    이 마스킹을 사용해 conic-gradient 를 의사적으로 표현하는 방법에 대해 설명합니다.

    1. 원형으로 그라데이션이 적용된 마스킹 요소를 생성합니다.



    이 부분이 키모가 됩니다만, rect 요소를 조금씩 회전시켜, 그리고 회전할 때마다 백색→흑색으로 변화시켜, 이하와 같은 이미지의 도형을 묘화합니다.



    도형을 그리면 원추형으로 그라데이션이 걸린 원이 완성됩니다. 구체적인 코드 예를 아래에 설명합니다.

    HTML
    <svg id="mySvg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 160 160" version="1.1">
      <defs>
        <mask id="angle">
          <g id="circleMask">
          </g>
        </mask>
      </defs>
    </svg>
    

    자바스크립트
    const changedDegree = 255;
    let mask = document.querySelector('#circleMask');
    
    function makeRGBA(degree){
      var ratio = 1 - Math.abs(degree / changedDegree);
      var colorVal = Math.floor(255 * ratio);
      var colorArray = [colorVal,colorVal,colorVal]
      return 'rgba('+colorArray.join(',')+',1)';
    }
    
    for(i = 1 ; i < changedDegree ; i++){
      let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
      rect.setAttribute('width', 80);
      rect.setAttribute('height', 80);
      rect.setAttribute('fill', makeRGBA(i));
      rect.setAttribute('transform', 'rotate('+ (i + 90) +' 80 80)');
      mask.appendChild(rect);
    }
    

    2. 도형에 마스킹 적용



    1에서 만든 마스킹 요소를 특정 SVG 요소에 적용합니다.

    HTML
    <circle r="60" cx="80" cy="80" fill="orange" mask="url(#angle)"/>
    

    그러면 다음과 같이 마스킹된 상태가 됩니다.



    3. 마스킹된 도형을 중첩



    그리고는 마스킹 된 SVG 요소와 같은 크기의 SVG 요소에 겹치면 완성입니다.

    HTML
    <circle r="60" cx="80" cy="80" fill="red"/>
    <circle r="60" cx="80" cy="80" fill="orange" mask="url(#angle)"/>
    



    소감


    conic-gradient 를 표현하는 것은 생각보다 쉬웠지만 성능이나 유지 보수성을 고려하면 linear-gradient 또는 radial-gradient 로 표현 가능한 디자인으로 변경하는 것이 바람직 할 수 있습니다.
    CSS4에서 conic-gradient 가 권고되는 날을 기다리고 싶습니다.

    좋은 웹페이지 즐겨찾기