{"id":3140,"date":"2019-11-22T14:12:50","date_gmt":"2019-11-22T14:12:50","guid":{"rendered":"https:\/\/rengga.dev\/blog\/?p=3140"},"modified":"2023-02-12T03:08:08","modified_gmt":"2023-02-12T03:08:08","slug":"css-tutorial-a-table-with-both-a-sticky-header-and-a-sticky-first-column","status":"publish","type":"post","link":"https:\/\/rengga.dev\/blog\/css-tutorial-a-table-with-both-a-sticky-header-and-a-sticky-first-column\/","title":{"rendered":"CSS Tutorial &#8211; A table with both a sticky header and a sticky first column"},"content":{"rendered":"<p><span style=\"color: #ef3207;\"><a style=\"color: #ef3207;\" href=\"https:\/\/rengga.dev\/\" target=\"_blank\" rel=\"noopener\"><strong>Rengga Dev<\/strong><\/a> <\/span>&#8211; We\u2019ve covered that\u00a0individual\u00a0<code>&lt;table&gt;<\/code>\u00a0cells,\u00a0<code>&lt;th&gt;<\/code>\u00a0and\u00a0<code>&lt;td&gt;<\/code>\u00a0can be\u00a0<code>position: sticky<\/code>. It\u2019s pretty easy to make the\u00a0<em>header<\/em>\u00a0of a table stick to the top of the screen while scrolling through a bunch or rows (like\u00a0<a href=\"https:\/\/codepen.io\/chriscoyier\/pen\/PrJdxb\" rel=\"noopener\">this demo<\/a>).<\/p>\n<p>But stickiness isn\u2019t just for the top of the screen, you can stick things in any scroll direction (horizontal is\u00a0<a href=\"https:\/\/www.bennadel.com\/blog\/3961-having-fun-with-the-horizontal-usage-of-position-sticky-in-angular-11-0-5.htm\" rel=\"noopener\">just as fun<\/a>). In fact, we can have multiple sticky elements stuck in different directions inside the same element, and even single elements that are stuck in multiple directions.<\/p>\n<p>Why would you do that?\u00a0<strong>Specifically for tabular data where cross-referencing is the point.<\/strong>\u00a0In this table (which represents, of course, the scoring baseball game where somehow 20 teams are all playing each other at once because that\u2019s how baseball works), it \u201cmakes sense\u201d that you wouldn\u2019t want the team name or the inning number to scroll away, as you\u2019d lose context of what you\u2019re looking at.<br \/>\n<iframe style=\"width: 100%;\" title=\"Table with Sticky Header and Sticky First Column\" src=\"https:\/\/codepen.io\/renggagumilar\/embed\/XWEGzJE?default-tab=result&amp;theme-id=dark\" height=\"500\" frameborder=\"no\" scrolling=\"no\" allowfullscreen=\"allowfullscreen\"><br \/>\nSee the Pen <a href=\"https:\/\/codepen.io\/renggagumilar\/pen\/XWEGzJE\"><br \/>\nTable with Sticky Header and Sticky First Column<\/a> by Rengga Gumilar (<a href=\"https:\/\/codepen.io\/renggagumilar\">@renggagumilar<\/a>)<br \/>\non <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<br \/>\n<\/iframe><\/p>\n<p>The \u201ctrick\u201d at play here is partially the\u00a0<code>position: sticky;<\/code>\u00a0usage, but moreso to me, how you have to handle overlapping elements. A table cell that is sticky needs to have a background, because otherwise we\u2019ll see overlapping content. It also needs proper\u00a0<code>z-index<\/code>\u00a0handling so that when it sticks in place, it\u2019ll be on top of what it is supposed to be on top of. This feels like the trickiest part:<\/p>\n<ul>\n<li>Make sure the\u00a0<code>tbody&gt;th<\/code>\u00a0cells are above regular table cells, so they stay on top during a horizontal scroll.<\/li>\n<li>Make sure the\u00a0<code>thead&gt;th<\/code>\u00a0cells are above those, for vertical scrolling.<\/li>\n<li>Make sure the\u00a0<code>thead&gt;th:first-child<\/code>\u00a0cell is the very highest, as it needs to be above the body cells and it\u2019s sibling headers again for horizontal scrolling.<\/li>\n<\/ul>\n<p>A bit of a dance, but it\u2019s doable.<\/p>\n<p>High five to Cameron\u00a0Clark who emailed me\u00a0<a href=\"https:\/\/codepen.io\/capnhairdo\/pen\/qBaGRBV\" rel=\"noopener\">demoed this<\/a>\u00a0and showed me how cool it is. And indeed, Cameron, it is cool. When I shared that around, Estelle Weyl showed me\u00a0<a href=\"https:\/\/codepen.io\/estelle\/pen\/MNwVxW\" rel=\"noopener\">a demo<\/a>\u00a0she made several years ago. That feels about right, Estelle is always a couple of years ahead of me.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rengga Dev &#8211; We\u2019ve covered that\u00a0individual\u00a0&lt;table&gt;\u00a0cells,\u00a0&lt;th&gt;\u00a0and\u00a0&lt;td&gt;\u00a0can be\u00a0position: sticky. It\u2019s pretty easy to <a class=\"read-more\" href=\"https:\/\/rengga.dev\/blog\/css-tutorial-a-table-with-both-a-sticky-header-and-a-sticky-first-column\/\" title=\"CSS Tutorial &#8211; A table with both a sticky header and a sticky first column\" itemprop=\"url\"><\/a><\/p>\n","protected":false},"author":1,"featured_media":3180,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,2],"tags":[303,268,304,197,305,103,227],"newstopic":[],"class_list":{"0":"post-3140","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-html-css","8":"category-web-design","9":"tag-a-table-with-both-a-sticky-header","10":"tag-css-grid","11":"tag-css-table","12":"tag-css-tutorial","13":"tag-sticky-first-column","14":"tag-web-design","15":"tag-web-designer"},"_links":{"self":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3140","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/comments?post=3140"}],"version-history":[{"count":1,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3140\/revisions"}],"predecessor-version":[{"id":3141,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3140\/revisions\/3141"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/media\/3180"}],"wp:attachment":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/media?parent=3140"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/categories?post=3140"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/tags?post=3140"},{"taxonomy":"newstopic","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/newstopic?post=3140"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}