{"id":265970,"date":"2018-02-09T07:24:57","date_gmt":"2018-02-09T14:24:57","guid":{"rendered":"http:\/\/css-tricks.com\/?p=265970"},"modified":"2018-02-09T08:26:55","modified_gmt":"2018-02-09T15:26:55","slug":"direction-aware-hover-effects","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/direction-aware-hover-effects\/","title":{"rendered":"Direction Aware Hover Effects"},"content":{"rendered":"

This is a particular design trick that never fails to catch people’s eye! I don’t know the exact history of who-thought-of-what first and all that, but I know I have seen a number of implementations of it over the years. I figured I’d round a few of them up here.<\/p>\n

<\/p>\n

Noel Delagado<\/h3>\n

See the Pen Direction-aware 3D hover effect (Concept)<\/a> by Noel Delgado (@noeldelgado<\/a>) on CodePen<\/a>.<\/p>\n

The detection here is done by tracking the mouse position on mouseover<\/code> and mouseout<\/code> and calculating which side was crossed. It’s a small amount of clever JavaScript, the meat of which is figuring out that direction:<\/p>\n

var getDirection = function (ev, obj) {\r\n    var w = obj.offsetWidth,\r\n        h = obj.offsetHeight,\r\n        x = (ev.pageX - obj.offsetLeft - (w \/ 2) * (w > h ? (h \/ w) : 1)),\r\n        y = (ev.pageY - obj.offsetTop - (h \/ 2) * (h > w ? (w \/ h) : 1)),\r\n        d = Math.round( Math.atan2(y, x) \/ 1.57079633 + 5 ) % 4;\r\n  \r\n    return d;\r\n};<\/code><\/pre>\n

Then class names are applied depending on that direction to trigger the directional CSS animations. <\/p>\n

Fabrice Weinberg<\/h3>\n

See the Pen Direction aware hover pure CSS<\/a> by Fabrice Weinberg (@FWeinb<\/a>) on CodePen<\/a>.<\/p>\n

Fabrice uses just pure CSS here. They don’t detect the outgoing direction, but they do detect the incoming direction by way of four hidden hoverable boxes, each rotated to cover a triangle. Like this:<\/p>\n

Codrops<\/h3>\n
Demo<\/a><\/figcaption><\/figure>\n

In an article by Mary Lou on Codrops from 2012, Direction-Aware Hover Effect with CSS3 and jQuery<\/a>, the detection is also done in JavaScript<\/a>. Here’s that part of the plugin:<\/p>\n

_getDir: function (coordinates) {\r\n    \/\/ the width and height of the current div\r\n    var w = this.$el.width(),\r\n        h = this.$el.height(),\r\n        \/\/ calculate the x and y to get an angle to the center of the div from that x and y.\r\n        \/\/ gets the x value relative to the center of the DIV and \"normalize\" it\r\n        x = (coordinates.x - this.$el.offset().left - (w \/ 2)) * (w > h ? (h \/ w) : 1),\r\n        y = (coordinates.y - this.$el.offset().top - (h \/ 2)) * (h > w ? (w \/ h) : 1),\r\n        \/\/ the angle and the direction from where the mouse came in\/went out clockwise (TRBL=0123);\r\n        \/\/ first calculate the angle of the point,\r\n        \/\/ add 180 deg to get rid of the negative values\r\n        \/\/ divide by 90 to get the quadrant\r\n        \/\/ add 3 and do a modulo by 4 to shift the quadrants to a proper clockwise TRBL (top\/right\/bottom\/left) **\/\r\n        direction = Math.round((((Math.atan2(y, x) * (180 \/ Math.PI)) + 180) \/ 90) + 3) % 4;\r\n    return direction;\r\n},<\/code><\/pre>\n

It’s technically CSS doing the animation though, as inline styles are applied as needed to the elements.<\/p>\n

John Stewart<\/h3>\n

See the Pen Direction Aware Hover Goodness<\/a> by John Stewart (@johnstew<\/a>) on CodePen<\/a>.<\/p>\n

John leaned on Greensock to do all the detection and animation work here. Like all the examples, it has its own homegrown geometric math to calculate the direction in which the elements were hovered.<\/p>\n

\/\/ Detect Closest Edge\r\nfunction closestEdge(x,y,w,h) {\r\n    var topEdgeDist = distMetric(x,y,w\/2,0);\r\n    var bottomEdgeDist = distMetric(x,y,w\/2,h);\r\n    var leftEdgeDist = distMetric(x,y,0,h\/2);\r\n    var rightEdgeDist = distMetric(x,y,w,h\/2);\r\n    var min = Math.min(topEdgeDist,bottomEdgeDist,leftEdgeDist,rightEdgeDist);\r\n    switch (min) {\r\n        case leftEdgeDist:\r\n            return \"left\";\r\n        case rightEdgeDist:\r\n            return \"right\";\r\n        case topEdgeDist:\r\n            return \"top\";\r\n        case bottomEdgeDist:\r\n            return \"bottom\";\r\n    }\r\n}\r\n\r\n\/\/ Distance Formula\r\nfunction distMetric(x,y,x2,y2) {\r\n    var xDiff = x - x2;\r\n    var yDiff = y - y2;\r\n    return (xDiff * xDiff) + (yDiff * yDiff);\r\n}<\/code><\/pre>\n

Gabrielle Wee<\/h3>\n

See the Pen CSS-Only Direction-Aware Cube Links<\/a> by Gabrielle Wee ✨ (@gabriellewee<\/a>) on CodePen<\/a>.<\/p>\n

Gabrielle gets it done entirely in CSS by positioning four hoverable child elements which trigger the animation on a sibling element (the cube) depending on which one was hovered. There is some tricky stuff here involving clip-path<\/code> and transforms that I admit I don’t fully understand. The hoverable areas don’t appear to be triangular like you might expect, but rectangles covering half the area. It seems like they would overlap ineffectively, but they don’t seem to. I think it might be that they hang off the edges slightly giving a hover area that allows each edge full edge coverage.<\/p>\n

Elmer Balbin<\/h3>\n

See the Pen Direction Aware Tiles using clip-path Pure CSS<\/a> by Elmer Balbin (@elmzarnsi<\/a>) on CodePen<\/a>.<\/p>\n

Elmer is also using clip-path here, but the four hoverable elements are clipped into triangles. You can see how each of them has a point at 50% 50%, the center of the square, and has two other corner points.<\/p>\n

clip-path: polygon(0 0, 100% 0, 50% 50%)\r\nclip-path: polygon(100% 0, 100% 100%, 50% 50%);\r\nclip-path: polygon(0 100%, 50% 50%, 100% 100%);\r\nclip-path: polygon(0 0, 50% 50%, 0 100%);<\/code><\/pre>\n

Nigel O Toole<\/h3>\n
Demo<\/a><\/figcaption><\/figure>\n

Raw JavaScript powers Nigel’s demo here<\/a>, which is all modernized to work with npm and modules and all that. It’s familiar calculations though:<\/p>\n

const _getDirection = function (e, item) {\r\n  \/\/ Width and height of current item\r\n  let w = item.offsetWidth;\r\n  let h = item.offsetHeight;\r\n  let position = _getPosition(item);\r\n\r\n  \/\/ Calculate the x\/y value of the pointer entering\/exiting, relative to the center of the item.\r\n  let x = (e.pageX - position.x - (w \/ 2) * (w > h ? (h \/ w) : 1));\r\n  let y = (e.pageY - position.y - (h \/ 2) * (h > w ? (w \/ h) : 1));\r\n\r\n  \/\/ Calculate the angle the pointer entered\/exited and convert to clockwise format (top\/right\/bottom\/left = 0\/1\/2\/3).  See https:\/\/stackoverflow.com\/a\/3647634 for a full explanation.\r\n  let d = Math.round(Math.atan2(y, x) \/ 1.57079633 + 5) % 4;\r\n\r\n  \/\/ console.table([x, y, w, h, e.pageX, e.pageY, item.offsetLeft, item.offsetTop, position.x, position.y]);\r\n\r\n  return d;\r\n};<\/code><\/pre>\n

The JavaScript ultimately applies classes, which are animated in CSS based on some fancy Sass-generated animations<\/a>. <\/p>\n

Giana<\/h3>\n

A CSS-only take that handles the outgoing direction nicely!<\/p>\n

See the Pen CSS-only directionally aware hover<\/a> by Giana (@giana<\/a>) on CodePen<\/a>.<\/p>\n


\n

Seen any others out there? Ever used this on something you’ve built?<\/p>\n","protected":false},"excerpt":{"rendered":"

This is a particular design trick that never fails to catch people’s eye! I don’t know the exact history of who-thought-of-what first and all that, but I know I have seen a number of implementations of it over the years. I figured I’d round a few of them up here.<\/p>\n","protected":false},"author":3,"featured_media":266441,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[1373],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/01\/direction-aware-hovers.gif?fit=607%2C303&ssl=1","jetpack-related-posts":[],"featured_media_src_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/01\/direction-aware-hovers.gif?fit=607%2C303&ssl=1","_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/265970"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=265970"}],"version-history":[{"count":8,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/265970\/revisions"}],"predecessor-version":[{"id":266459,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/265970\/revisions\/266459"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/266441"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=265970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=265970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=265970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}