Skip to content

Instantly share code, notes, and snippets.

@CodeMyUI
Created Mar 24, 2019
Embed
What would you like to do?
SVG clip-path Hover Effect
:ruby
@items = [
{ :t => 'X-rays', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-xrays.png' },
{ :t => 'Worms', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-worms.png' },
{ :t => 'Aurora', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-aurora.png' },
{ :t => 'Angus', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-angus.png' },
{ :t => 'Huitzi', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-huitzi.png' },
{ :t => 'Dalí', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-dali.png' },
{ :t => 'The Bride', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-bride.png' },
{ :t => 'The Man', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-man.png' },
{ :t => 'D', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-d.png' },
{ :t => 'V', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-v.png' },
{ :t => 'V II', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-v2.png' },
{ :t => 'V III', :i => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-v3.png' }
]
.container
%header
%h1 SVG clip-path Hover Effect
%p
Attempt to re-create <a href="http://www.cjgammon.com/" target="_blank">CJ Gammon’s</a>
portfolio grid hover effect using SVG and CSS Transitions.
%p.small
<b>Note:</b> this is an experiment, it does not seem to work on Firefox 43.0.4
neither have touch support.
<br/>Tested on Chrome 47.0.2526.106, Opera 34.0 and Safari 8.0.6.
%main
.items
- @items.each_with_index do | item, index |
.item
%svg{:viewBox => "0 0 300 200", :preserveAspectRatio => "xMidYMid slice"}
%defs
%clipPath{:id => "clip-#{index}"}
%circle{:cx => "0", :cy => "0", :r => "150px", :fill => "#000"}
%text{:class => "svg-text", :x => "50%", :y => "50%", :dy => ".3em"}
#{item[:t]}
%g{:"clip-path" => "url(#clip-#{index})"}
%image{"xlink:href" => "#{item[:i]}", :width => "100%", :height => "100%", :preserveAspectRatio => "xMinYMin slice"}
%text{:class => "svg-masked-text", :x => "50%", :y => "50%", :dy => ".3em"}
#{item[:t]}
.options
%button.dark
%button.light
/*
* Noel Delgado | @pixelia_me
*/
var items = []
, point = document.querySelector('svg').createSVGPoint();
function getCoordinates(e, svg) {
point.x = e.clientX;
point.y = e.clientY;
return point.matrixTransform(svg.getScreenCTM().inverse());
}
function changeColor(e) {
document.body.className = e.currentTarget.className;
}
function Item(config) {
Object.keys(config).forEach(function (item) {
this[item] = config[item];
}, this);
this.el.addEventListener('mousemove', this.mouseMoveHandler.bind(this));
this.el.addEventListener('touchmove', this.touchMoveHandler.bind(this));
}
Item.prototype = {
update: function update(c) {
this.clip.setAttribute('cx', c.x);
this.clip.setAttribute('cy', c.y);
},
mouseMoveHandler: function mouseMoveHandler(e) {
this.update(getCoordinates(e, this.svg));
},
touchMoveHandler: function touchMoveHandler(e) {
e.preventDefault();
var touch = e.targetTouches[0];
if (touch) return this.update(getCoordinates(touch, this.svg));
}
};
[].slice.call(document.querySelectorAll('.item'), 0).forEach(function (item, index) {
items.push(new Item({
el: item,
svg: item.querySelector('svg'),
clip: document.querySelector('#clip-'+index+' circle'),
}));
});
[].slice.call(document.querySelectorAll('button'), 0).forEach(function (button) {
button.addEventListener('click', changeColor);
});
$db: #2f3238;
$dc: #f5f5f5;
$lb: #f9f9f9;
$lc: #1a1a1a;
$l: #1abc89;
* {margin: 0; box-sizing: border-box;}
:root {
font-size: 13px;
font-family: 'Source Sans Pro', sans-serif;
line-height: 1.618;
font-weight: 400;
}
body {
background-color: $db;
color: $dc;
}
a {color: $l}
a:hover {opacity: .8}
p {
font-size: 1.2rem;
color: rgba($dc, .5);
}
.small {
font-size: 1rem;
margin-top: 1em;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 4rem 2rem;
}
header {
text-align: center;
padding-bottom: 3rem;
}
h1 {
font-size: 2.6rem;
line-height: 1.2em;
padding-bottom: 1rem;
font-weight: 600;
}
svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
circle {
transform-origin: 50% 50%;
transform: scale(0);
transition: transform 200ms cubic-bezier(0.250, 0.460, 0.450, 0.940);
}
text {
font-size: 1.1rem;
text-transform: uppercase;
text-anchor: middle;
letter-spacing: 1px;
font-weight: 600;
}
.svg-text {fill: lighten($db, 16)}
.svg-masked-text {fill: rgba(#fff, 1);}
image {
transform: scale(1.1);
transform-origin: 50% 50%;
transition: transform 200ms cubic-bezier(0.250, 0.460, 0.450, 0.940);
}
.items {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.item {
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
width: 300px;
height: 200px;
margin: 5px;
cursor: pointer;
background-color: lighten($db, 5);
border-radius: 2px;
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.02), inset 0 0px 0px 1px rgba(0, 0, 0, 0.07);
transform: translateZ(0);
}
.item:hover {
circle,
image {transform: scale(1)}
}
button {
width: 12px;
height: 12px;
border: none;
appearance: none;
box-shadow: 0 0 0 1px rgba(0,0,0,.5);
border-radius: 1px;
&.dark {background-color: $db;}
&.light {background-color: $lb;}
}
.options {
position: absolute;
top: 1rem;
right: 1rem;
button {margin-left: .5rem}
}
.light {
background-color: $lb;
color: $lc;
p {color: rgba($lc, .5);}
.item {background: $dc;}
.svg-text {fill: rgba(#000, .1);}
}

SVG clip-path Hover Effect

Attempt to re-create CJ Gammon’s portfolio grid hover effect using SVG clip-path and CSS Transitions.

A Pen by Noel Delgado on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment