{"id":282039,"date":"2019-02-05T12:04:42","date_gmt":"2019-02-05T19:04:42","guid":{"rendered":"http:\/\/css-tricks.com\/?p=282039"},"modified":"2019-02-05T12:04:42","modified_gmt":"2019-02-05T19:04:42","slug":"using-the-little-known-css-element-function-to-create-a-minimap-navigator","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-the-little-known-css-element-function-to-create-a-minimap-navigator\/","title":{"rendered":"Using the Little-Known CSS element() Function to Create a Minimap Navigator"},"content":{"rendered":"
W3C\u2019s CSS Working Group often gives us brilliant CSS features to experiment with. Sometimes we come across something so cool that sticks a grin on our face, but it vanishes right away because we think, \u201cthat\u2019s great, but what do I do with it?\u201d The <\/p>\n Below is a simple example<\/a> of how it works. It\u2019s currently only supported in Firefox, which I know is a bummer. But stick with me and see how useful it can be.<\/p>\n The When I think of A minimap<\/strong> is a mini-sized preview of a long document or page, usually shown at on one side of the screen or another and used to navigate to a corresponding point on that document.<\/p>\n You might have seen it in code editors like Sublime Text.<\/p>\n Down below is the demo for the minimap, and we will walk through its code after that. However, I recommend you see the full-page demo<\/a> because minimaps are really useful for long<\/em> documents on large<\/em> screens.<\/p>\n If you\u2019re using a smartphone, remember that, according to the theory of relativity, minimaps will get super mini in mini screens; and no, that\u2019s not really what the theory of relativity actually says, but you get my point.<\/p>\n \nSee the Pen Minimap with CSS element() & HTML input range<\/a> by Preethi Sam (@rpsthecoder<\/a>) on CodePen<\/a>.<\/span><\/p>\n If you\u2019re designing the minimap for the whole page, like for a single page website, you can use the document body element for the image. Otherwise, targeting the main content element, like the article in my demo, also works.<\/p>\n For the minimap\u2019s background image, we feed the The minimap is also fixed to the screen at top right of the viewport.<\/p>\n Once the background is ready, we can add a slider on top of it and it will serve to operate the minimap scrolling. For the slider, I went with Not entirely<\/em> uncomplicated because it did need some tweaking. I turned the slider upright, to match the minimap, and applied some style to its pseudo elements (specifically, the thumb and track) to replace their default styles. Again, we\u2019re only concerned about Firefox at the moment since we\u2019re dealing with limited support.<\/p>\n All that\u2019s left is to couple the slider\u2019s value to a corresponding scroll point on the page when the value is changed by the user. That takes a sprinkle of JavaScript, which looks like this:<\/p>\n The dollar sign ( It\u2019s worth noting that the width of the minimap is already set in the CSS, so we really only need to calculate its height. So, we\u2018re dealing with the height of the minimap and the width of the slider because, remember, the slider is actually rotated up.<\/p>\n Here\u2019s how the equation in the script was determined, starting with the variables:<\/p>\n And, when the value of the slider changes ( Obviously, there are going to be plenty<\/em> of times when We check for feature support in CSS:<\/p>\n …or in JavaScript:<\/p>\n If you don\u2019t mind the background image being absent, then you can still keep the slider and apply a different style on it.<\/p>\n There are other slick ways to make minimaps that are floating out in the wild (and have more browser support). Here\u2019s a great Pen by Shaw<\/a>:<\/p>\n \nSee the Pen There are also tools like pagemap<\/a> and xivimap<\/a> that can help. The This browser support data is from Caniuse<\/a>, which has more detail. A number indicates that browser supports the feature at that version and up.<\/p><\/div>element()<\/code> function was like that for me. It\u2019s a CSS function that takes an element on the page and presents it as an image to be displayed on screen. Impressive, but quixotic.<\/p>\n<div id=\"ele\">\r\n <p>Hello World! how're you?<br>I'm not doing that<br>great. Got a cold 😷<\/p>\r\n<\/div>\r\n<div id=\"eleImg\"><\/div><\/code><\/pre>\n#eleImg {\r\n background: -moz-element(#ele) no-repeat center \/ contain; \/* vendor prefixed *\/\r\n}<\/code><\/pre>\nelement()<\/code> function (with browser prefix) takes the id<\/code> value of the element it\u2019ll translate into an image. The output looks identical to the appearance of the given element on screen.<\/p>\n
<\/figure>\nelement()<\/code>\u2019s output, I think of the word preview<\/strong>. I think that\u2019s the type of use case that gets the most out of it: where we can preview an element before it\u2019s shown on the page. For example, the next slide in a slideshow, the hidden tab, or the next photo in a gallery. Or… a minimap!<\/p>\n
CSS element()<\/code> is useful in making the \u201cpreview\u201d part of the minimap.<\/strong><\/p>\n
<\/figure>\n<div id=\"minimap\"><\/div>\r\n<div id=\"article\"> <!-- content --> <\/div><\/code><\/pre>\n#minimap {\r\n background: rgba(254,213,70,.1) -moz-element(#article) no-repeat center \/ contain;\r\n position: fixed; right: 10px; top: 10px; \/* more style *\/\r\n}<\/code><\/pre>\nid<\/code> of the article as the parameter of element()<\/code> and, like with most background images, it\u2019s styled to not repeat (no-repeat<\/code>) and fit inside (contain<\/code>) and at center of the box (center<\/code>) where it\u2019s displayed.<\/p>\ninput: range<\/code>, the original, uncomplicated, and plain HTML slider.<\/p>\n<div id=\"minimap\">\r\n <input id=\"minimap-range\" type=\"range\" max=\"100\" value=\"0\">\r\n<\/div><\/code><\/pre>\n#minimap-range {\r\n \/* Rotating the default horizontal slider to vertical *\/\r\n transform: translateY(-100%) rotate(90deg);\r\n transform-origin: bottom left;\r\n background-color: transparent; \/* more style *\/\r\n}\r\n\r\n#minimap-range::-moz-range-thumb {\r\n background-color: dodgerblue; \r\n cursor: pointer; \/* more style *\/\r\n}\r\n\r\n#minimap-range::-moz-range-track{\r\n background-color: transparent;\r\n}<\/code><\/pre>\nonload = () => {\r\n const minimapRange = document.querySelector(\"#minimap-range\");\r\n const minimap = document.querySelector(\"#minimap\");\r\n const article = document.querySelector(\"#article\");\r\n const $ = getComputedStyle.bind();\r\n \r\n \/\/ Get the minimap range width multiplied by the article height, then divide by the article width, all in pixels.\r\n minimapRange.style.width = minimap.style.height = \r\n parseInt($(minimapRange).width) * parseInt($(article).height) \/ parseInt($(article).width) + \"px\";\r\n \r\n \/\/ When the range changes, scroll to the relative percentage of the article height \r\n minimapRange.onchange = evt => \r\n scrollTo(0, parseInt($(article).height) * (evt.target.value \/ 100));\r\n};<\/code><\/pre>\n$<\/code>) is merely an alias for getComputedStyle()<\/code>, which is the method to get the CSS values of an element.<\/p>\n\n
x1\/y1 = x2\/y2\r\nx1 = y1 * x2\/y2\r\n \r\nheight of minimap = width of minimap * height of article \/ width of article<\/code><\/pre>\nminimapRange.onchange<\/code>), that\u2019s when the ScrollTo()<\/code> method is called to scroll the page to its corresponding value on the article. 💥<\/p>\nFallbacks! We need fallbacks!<\/h3>\n
element()<\/code> is not supported if we were to use this at the moment, so we might want to hide the minimap in those cases.<\/p>\n@supports (background: element(#article)) or (background: -moz-element(#article)){\r\n \/* fallback style *\/\r\n}<\/code><\/pre>\nif(!CSS.supports('(background: element(#article)) or (background: -moz-element(#article))')){\r\n \/* fallback code *\/\r\n}<\/code><\/pre>\n
\nMini-map Progress Tracker & Scroll Control<\/a> by Shaw (@shshaw<\/a>)
\non CodePen<\/a>.<\/span>\n<\/p>\nelement()<\/code> function is currently specced in W3C\u2019s CSS Image Values and Replaced Content Module Level 4<\/a>. Defintely worth a read to fully grasp the intention and thought behind it.<\/p>\n