CodePen

HTML

            
              <div class='outer-wrap round'>
	<ul class='quadrants fill'>
		<li class='q'>Q I</li>
		<li class='q'>Q II</li>
		<li class='q'>Q III</li>
		<li class='q'>Q IV</li>
	</ul>
	<div class='box centre-me'></div>
	<div class='axis angle-start-axis centre-me'></div>
	<div class='axis h-axis centre-me'></div>
	<div class='moving-line grad-line centre-me'></div>
	<div class='moving-line grad-start centre-me'></div>
	<div class='moving-line grad-end centre-me'></div>
	<ul class='angles fill round'></ul>
</div>
<code class='grad-code'></code>
            
          
!

CSS

            
              html, body { min-width: 240px; min-height: 240px; height: 100%; }
html {
  overflow: hidden;
  background: gainsboro;
  font: .8em Verdana, sans-serif; text-align: center; }
body { overflow: auto; margin: 0 0 -1em; }
.centre-me { position: absolute; top: 50%; left: 50%; }
.fill { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: 0; }
.round { border-radius: 50%; }
.outer-wrap {
	position: relative;
	margin: 4em auto 1em;
}
.outer-wrap ul { list-style: none; }
.q { position: absolute; font-weight: 700; }
.q:first-child { top: -1em; right: -1em; }
.q:nth-child(2) { right: -1em; bottom: -1em; }
.q:nth-child(3) { bottom: -1em; left: -1em; }
.q:nth-child(4) { top: -1em; left: -1em; }
.angles { transform: rotate(-90deg); }
.angle {
	margin: -1px;
	border: solid 1px;
	cursor: pointer;
	transition: box-shadow .3s;
}
.angle:after {
	position: absolute;
	top: 50%; left: 50%;
	margin: -7px;
	width: 14px; height: 14px;
	border-radius: 50%;
	content: '';
}
.angle:before {
	position: absolute;
	top: -10px; left: 11px;
	padding: 0 3px;
	border-radius: 4px;
	box-shadow: 0 0 2px;
	background: linear-gradient(whitesmoke, gainsboro);
	color: black;
}
.sec:before { transform: rotate(180deg); }
.angle:hover, .selected {
	box-shadow: 0 0 1px 3px crimson, 0 0 1px 5px white, 0 0 1px 7px crimson;
}
.angle:hover:before, .selected:before { content: attr(data-angle) '°'; }
.major {
	margin: -2px;
	border: solid 2px;
	color: crimson;
}
.box {
	margin: -15% -30%;
	width: 60%;
	height: 30%;
	background: linear-gradient(0deg, deeppink, yellow, springgreen);
  transition: background-image .75s linear;
}
.axis { top: -50px; bottom: -50px; width: 1px; background: dimgrey; }
.angle-start-axis:before {
	display: block;
	min-width: 125px;
	text-align: left;
	text-indent: 2px;
	content: '← angle start axis';
}
.h-axis { transform: rotate(90deg); }
.grad-line {
	top: 12px; bottom: 12px;
	width: 1px;
	background: dodgerblue;
	transition: transform .75s linear;
}
.grad-line:before {
	display: block;
	margin-top: 7px;
	min-width: 105px;
	text-align: left;
	text-indent: 2px;
	content: '← gradient line';
}
.rev:before { transform: rotate(180deg); content: 'gradient line →'; }
.grad-start, .grad-end {
	left: 20%; right: 20%;
	height: 1px;
	background: crimson;
	transition: .75s linear;
}
.grad-end { background: black; }
.grad-code {
	display: inline-block;
  position: relative;
  z-index: 1;
  margin-top: 3em;
	padding: .5em;
	background: black;
	color: white;
	font: 1.25em monospace;
}

@media (min-width: 240px) {
	html { overflow-x: hidden; }
}
            
          
!
? ?
? ?
Must be a valid URL.
+ add another resource
via CSS Lint

JS

            
              /*
 * JUST CLICK THE DOTS TO PICK A NEW ANGLE
 * 
 * Used as a helper demo for 
 * http://hugogiraudel.com/blog/css-gradients
 * 
 * See Details Tab.
 */


(function() {
  var fullCircle = 360,
      Demo = function() {
        // utility class
        var EUtil = function() {
          this.getSize = function(m /* integer */) {
            var w = document.body.clientWidth, h = document.body.clientHeight, s;
            s = Math.max(Math.min(Math.min(w,h) - m - 96, 640), 199);
            return (s%2 !== 0)?s:(s-1);
          }

          this.setStyle = function(elStyles) {
            /*
        elStyles is an array
        [
          [element_1, {property_1_1: value_1_1, property_1_2: value_1_2}], 
          [element_2, {property_2_1: value_2_1}]
        ]
        */
            var t, len = elStyles.length,
                prefixed = {'property': ['transform'], 'value': ['linear-gradient']}, 
                prefixList = ['-webkit-', '-moz', '-o-'], l = prefixList.length;
            for(var i = 0; i < len; i++) {
              for(var p in elStyles[i][1]) {
                if(prefixed['property'][0].indexOf(p) != -1) { /* check if the property needs to be prefixed */
                  for(var j = 0; j < l; j++)
                    elStyles[i][0].style[prefixList[j] + p] = elStyles[i][1][p];
                }
                if(elStyles[i][1][p].indexOf(prefixed['value'][0]) != -1) { /* check if the value needs to be prefixed */
                  t = 90 - parseInt(elStyles[i][1][p].split(prefixed['value'][0]+'(')[1].split('deg')[0], 10);
                  t = prefixed['value'][0] + '(' + t + 'deg' + elStyles[i][1][p].split('deg')[1];
                  for(var j = 0; j < l; j++)
                    elStyles[i][0].style[p] = prefixList[j] + t;
                }
                elStyles[i][0].style[p] = elStyles[i][1][p]; /* just set styles, no prefixes */
              }
            }
          };
        };

        // angle class
        var Angle = function(angleValue, u, r) {
          var value = angleValue, 
              selected = (angleValue === 0)?true:false, 
              el = document.createElement('li'); /* this is a dot on the circle */
          el.setAttribute('class', 'angle centre-me round');
          this.isSelected = function() 	{ return selected; };
          this.select = function() 		  { selected = true; el.classList.add('selected'); };
          this.unselect = function() 		{ selected = false; el.classList.remove('selected'); };
          this.getValue = function() 		{ return value; };
          this.getElement = function() 	{ return el; };
          this.isMajor = function()		  { return value%15 === 0; };
          this.isSec = function()			  { return value > 180; };
          if(this.isMajor()) el.classList.add('major');
          if(this.isSec()) el.classList.add('sec');
          if(this.isSelected()) el.classList.add('selected');
          if(el.dataset) el.dataset.angle = value;
          else el.setAttribute('data-angle', value);
          u.setStyle([[el, {'transform': 'rotate(' + value + 'deg) translate(' + r + 'px)'}]]);
        };

        var AngleCircle = function() {
          var angles = [], currentAngle, 
              getSensitivity = function(size) {
                if(size < 240) return 15; /* every 15° for smallest screen */
                if(size < 320) return 10; /* every 10° */
                if(size < 480) return 6;
                if(size < 560) return 5;
                return 3;
              }

          this.createCircle = function(parent, u) {
            var parentStyle = window.getComputedStyle(parent, null), 
                margin = parseInt(parentStyle.marginTop.split('px')[0], 10) + 36, 
                size = u.getSize(margin), r = size/2, s = getSensitivity(size), 
                listWrap = parent.querySelector('.angles');
            u.setStyle([[parent, {'width': size + 'px', 'height': size + 'px'}]]);
            listWrap.innerHTML = '';
            listWrap = parent.removeChild(listWrap);
            for(var i = 0; i < fullCircle/s; i++) {
              currentAngle = new Angle(i*s, u, r);
              angles.push(currentAngle);
              listWrap.appendChild(currentAngle.getElement());
            }
            parent.appendChild(listWrap);
          };

          this.getSelected = function() {
            var len = angles.length;
            for(var i = 0; i < len; i++)
              if(angles[i].isSelected()) return angles[i];
            console.log('error, no angle selected :(');
            return null;
          };

          this.getAngle = function(angleValue) {
            var len = angles.length;
            for(var i = 0; i < len; i++) 
              if(angles[i].getValue() == angleValue) return angles[i];
            console.log('error, no angle with such value :(');
            return null;
          };

          this.select = function(angleValue) {
            var len = angles.length, selectedAngle = this.getSelected();
            if(angleValue == selectedAngle.getValue()) {
              console.log('already selected :)');
              return -1;
            }
            this.getAngle(angleValue).select();
            selectedAngle.unselect();
          };
        };

        this.init = function() {
          var u = new EUtil(), wrap = document.querySelector('.outer-wrap'), 
              box = wrap.querySelector('.box'), 
              codeEl = document.querySelector('.grad-code'), 
              codetxt = 'linear-gradient(0deg, deeppink, yellow, lime)', 
              gradLine = document.querySelector('.grad-line'), 
              gradStart = document.querySelector('.grad-start'), 
              gradEnd = document.querySelector('.grad-end'), 
              angleCircle = new AngleCircle(), currentAngle = 0;

          angleCircle.createCircle(wrap, u);
          u.setStyle([[gradLine, {'transform': 'rotate(0)'}], 
                      [gradStart, {'transform': 'rotate(0)', 'left': '-10%', 'right': '50%', 'top': '65%'}], 
                      [gradEnd, {'transform': 'rotate(0)', 'left': '50%', 'right': '-10%', 'top': '35%'}], 
                      [box, {'backgroundImage': codetxt}]]);
          codeEl.innerHTML = codetxt;
          if(gradLine.classList.contains('rev')) gradLine.classList.remove('rev');

          wrap.addEventListener('click', function(e) {
            var t = e.target, a, dif;
            if(t.classList.contains('angle')) {
              if(t.dataset) a = parseInt(t.dataset.angle, 10);
              else a = parseInt(t.getAttribute('data-angle'), 10);
              if(angleCircle.select(a) == -1) return;
              dif = a - currentAngle%360;
              currentAngle += (Math.abs(dif) > 180) ? (Math.abs(dif) - 360)*Math.abs(dif)/dif : dif;
              codetxt = 'linear-gradient(' + currentAngle + 'deg, deeppink, yellow, lime)';
              u.setStyle([[gradLine, {'transform': 'rotate(' + currentAngle + 'deg)'}], 
                          [gradStart, {'transform': 'rotate(' + currentAngle + 'deg)'}], 
                          [gradEnd, {'transform': 'rotate(' + currentAngle + 'deg)'}], 
                          [box, {'backgroundImage': codetxt}]]);
              codetxt = 'linear-gradient(' + ((currentAngle%360>=0)?(currentAngle%360):(360+currentAngle%360)) + 'deg, deeppink, yellow, lime)';
              codeEl.innerHTML = codetxt;
              if(a > 90 && a < 270) gradLine.classList.add('rev');
              else gradLine.classList.remove('rev');
              if(a >= 0 && a < 90)
                u.setStyle([[gradStart, {'left': '-10%', 'right': '50%', 'top': '65%'}], 
                            [gradEnd, {'left': '50%', 'right': '-10%', 'top': '35%'}]]);
              if(a >= 90 && a < 180)
                u.setStyle([[gradStart, {'left': '-10%', 'right': '50%', 'top': '35%'}], 
                            [gradEnd, {'left': '50%', 'right': '-10%', 'top': '65%'}]]);
              if(a >= 180 && a < 270)
                u.setStyle([[gradStart, {'left': '50%', 'right': '-10%', 'top': '35%'}], 
                            [gradEnd, {'left': '-10%', 'right': '50%', 'top': '65%'}]]);
              if(a >= 270 && a < 360)
                u.setStyle([[gradStart, {'left': '50%', 'right': '-10%', 'top': '65%'}], 
                            [gradEnd, {'left': '-10%', 'right': '50%', 'top': '35%'}]]);

            }
          }, false);
        };
      }

  var d = new Demo();
  d.init();
  window.addEventListener('resize', function(e) { d.init(); }, false);
}());
            
          
!
Must be a valid URL.
+ add another resource
via JS Hint
Loading ..................