Skip to content

Instantly share code, notes, and snippets.

@m1r1c1
Forked from ttscoff/linkding-cards.css
Last active July 18, 2026 19:18
Show Gist options
  • Select an option

  • Save m1r1c1/0c463f7731e5c1c88a8b24d69a1b448a to your computer and use it in GitHub Desktop.

Select an option

Save m1r1c1/0c463f7731e5c1c88a8b24d69a1b448a to your computer and use it in GitHub Desktop.
Custom CSS to give linkding a dark, card-based layout
/*
Card-based layout for Linkding
Large images, fully clickable
Entire card selectable in bulk edit mode
Tags moved to expandable sidebar
01/11/2026 - MRC - Modified using Claude AI
to have CSS applied to Linkding 1.45. Also
modified to use same card style layout but
a little differently that meets my needs a
little better.
07/18/2026 - MRC - Modified using Claude AI
Fable to standardize and improve organization
of CSS. Should be no major functional change.
Author: Brett Terpstra (https://brettterpstra.com)
GitHub: @ttscoff <https://github.com/ttscoff>
Modified for updated Linkding version
License: MIT
Refactor notes:
- All colors are defined once in :root as RGB channel triplets, so both
solid colors and rgba() variants derive from a single source.
To re-theme the skin, edit only the "PALETTE" block below.
- Layout magic numbers are derived from a few anchor values (image height,
card padding, actions height). Formulas are noted where they were
inferred from the original hand-tuned values.
*/
:root {
/* ==========================================================
PALETTE — edit these triplets to re-theme the entire skin
========================================================== */
--bg-rgb: 0, 18, 25; /* page background (#001219) */
--mint-rgb: 148, 210, 189; /* light accent / links (#94d2bd) */
--teal-rgb: 10, 147, 150; /* mid accent / hovers (#0a9396) */
--deep-rgb: 0, 95, 115; /* buttons / tag pills (#005f73) */
--orange-rgb: 202, 103, 2; /* "redux" label (#ca6702) */
--cyan-bright-rgb: 15, 217, 222;/* link hover (#0fd9de) */
--danger-rgb: 220, 41, 23; /* delete / destructive (#dc2917) */
--danger-bright-rgb: 255, 42, 21; /* confirm-cancel "×" (#ff2a15) */
--tooltip-rgb: 0, 91, 127; /* title tooltip bg (#005b7f) */
--khaki-rgb: 153, 136, 87; /* action btn-link border */
--neutral-border-rgb: 51, 51, 51; /* card borders, notes (#333) */
--neutral-text-rgb: 170, 170, 170; /* description text (#aaa) */
/* Solid colors derived from the triplets */
--color-bg: rgb(var(--bg-rgb));
--color-mint: rgb(var(--mint-rgb));
--color-teal: rgb(var(--teal-rgb));
--color-deep: rgb(var(--deep-rgb));
--color-orange: rgb(var(--orange-rgb));
--color-cyan-bright: rgb(var(--cyan-bright-rgb));
--color-danger: rgb(var(--danger-rgb));
--color-danger-bright: rgb(var(--danger-bright-rgb));
--color-tooltip: rgb(var(--tooltip-rgb));
--color-border: rgb(var(--neutral-border-rgb));
--color-desc-text: rgb(var(--neutral-text-rgb));
/* ==========================================================
LAYOUT ANCHORS — dependent values derive from these
========================================================== */
--card-image-height: 200px; /* preview image height (the master value) */
--card-padding: 10px; /* inner card padding */
--card-border-width: 1px; /* card border */
--card-radius: 8px;
--actions-height: 70px; /* bottom action bar height */
--sidebar-width: 250px;
--header-clearance: 100px; /* sticky offset below the fixed header */
/* Derived layout values */
/* Top padding = image height + card padding (was 210px) */
--card-top-padding: calc(var(--card-image-height) + var(--card-padding));
/* Clickable image overlay = image height + 50px overlap (was 250px) */
--card-overlay-height: calc(var(--card-image-height) + 50px);
/* Bulk-edit checkbox: generous cover, 3x image height (was 600px) */
--bulk-checkbox-height: calc(var(--card-image-height) * 3);
/* Checkbox offsets: padding + border(s) (were -11px / -212px) */
--bulk-checkbox-left: calc(-1 * (var(--card-padding) + var(--card-border-width)));
--bulk-checkbox-top: calc(-1 * (var(--card-top-padding) + 2 * var(--card-border-width)));
/* Description overlay (expand-on-hover) */
--desc-top-offset: 3em; /* sits just below the title */
--desc-collapsed-height: 4.3em;
--desc-expanded-height: 15em;
/* URL clearance keeps the url line above the actions bar (was 7.3em) */
--url-bottom-clearance: 7.3em;
/* Notes tab (collapsed) */
--notes-tab-width: 44px;
--notes-tab-height: 23px;
--notes-tab-bottom: 34px;
/* ==========================================================
Linkding theme variables mapped onto the palette
========================================================== */
--primary-color: var(--color-mint);
--primary-text-color: #fff;
--btn-primary-bg-color: var(--color-deep);
--btn-primary-hover-bg-color: var(--color-teal);
--btn-primary-text-color: #fff;
--btn-link-text-color: var(--color-mint);
--btn-link-hover-text-color: var(--color-cyan-bright);
--checkbox-checked-bg-color: var(--color-deep);
--checkbox-bg-color: rgba(var(--deep-rgb), 0.75);
--tab-active-color: var(--color-mint);
--tab-highlight-color: var(--color-teal);
--tab-hover-color: var(--color-teal);
--focus-outline: var(--color-mint);
--input-border-color: #1e493a;
--btn-border-color: #1e493a;
}
body {
--fbc-blue-60: var(--color-bg);
--fbc-blue-70: var(--color-bg);
background: var(--color-bg);
margin-top: 0px;
}
/* Logo */
a {
color: var(--color-mint);
}
.btn {
color: var(--color-mint);
}
.btn .btn-primary {
background: var(--color-deep);
color: var(--color-mint);
}
.btn .btn-primary:hover {
color: var(--color-teal);
}
header h1 {
transform: rotate(-5deg) translate(-7px, -13px);
}
header h1::after {
color: var(--color-orange);
content: " redux";
left: 0;
opacity: 0.8;
position: absolute;
top: 1em;
}
/* Make header sticky */
header {
position: sticky;
top: 0;
z-index: 100;
background: var(--color-bg);
padding-top: 20px;
padding-bottom: 20px;
margin-bottom: 0px;
}
/* Tag cloud styling */
.tag-cloud .unselected-tags a {
border-radius: 15px;
border: solid 1px rgba(var(--deep-rgb), 0.3);
color: var(--color-deep);
display: inline-block;
font-weight: 500;
margin: 0 0 0.25em 0 !important;
padding: 0 6px;
transition: all 0.3s ease-in-out;
}
.tag-cloud .highlight-char {
color: var(--color-teal);
}
.tag-cloud .unselected-tags a:hover,
.tag-cloud .unselected-tags a:focus,
.tag-cloud .unselected-tags a:visited:hover,
.tag-cloud .unselected-tags a:visited:focus {
background: rgba(var(--mint-rgb), 0.8);
box-shadow: 0 0 4px rgba(var(--mint-rgb), 0.35);
text-decoration: none;
transform: scale(1.1);
transition: all 0.15s ease-in-out;
}
.tag-cloud a {
font-weight: 500;
}
/* Bookmark cards */
ul.bookmark-list>li {
background-color: rgba(var(--deep-rgb), 0.09);
border-radius: var(--card-radius);
border: solid var(--card-border-width) var(--color-border);
display: block;
gap: 0px 0px;
margin: 0 10px 10px 0;
min-width: 250px;
overflow: hidden;
padding: var(--card-top-padding) var(--card-padding) var(--card-padding) var(--card-padding);
position: relative;
width: 100%;
}
ul.bookmark-list>li .title img + a::before {
content: "";
display: block;
height: var(--card-overlay-height);
left: calc(-1 * var(--card-padding));
position: absolute;
top: calc(-1 * var(--card-overlay-height));
width: 110%;
z-index: 8;
}
ul.bookmark-list>li .preview-image {
height: var(--card-image-height);
left: 0;
position: absolute;
top: 0;
width: 100%;
}
ul.bookmark-list>li .title img {
top: var(--card-padding);
transition: transform 0.2s ease-in-out;
}
ul.bookmark-list>li .title:hover img {
transform: translateY(-50%) scale(1.3);
transition: transform 0.2s ease-in-out;
}
ul.bookmark-list>li .title a[data-tooltip]:focus::after,
ul.bookmark-list>li .title a[data-tooltip]:hover::after {
background: var(--color-tooltip);
border-color: var(--color-deep);
}
@media screen and (min-width: 770px) {
ul.bookmark-list>li {
width: 48%;
}
}
@media screen and (min-width: 900px) {
ul.bookmark-list>li {
width: 32%;
}
}
@media screen and (min-width: 1300px) {
ul.bookmark-list>li {
width: 24%;
}
}
/* Make image clickable */
ul.bookmark-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
ul.bookmark-list>li .title {
background: 0;
}
ul.bookmark-list>li .content {
display: block;
height: 100%;
max-width: 100%;
padding-bottom: var(--actions-height);
position: relative;
width: 100%;
}
ul.bookmark-list>li .title a {
width: 100%;
color: #fff;
}
ul.bookmark-list>li .url-display,
ul.bookmark-list>li .url-path {
margin-bottom: var(--url-bottom-clearance);
color: var(--color-mint);
}
/* Re-enable grid for bookmarks page to show sidebar */
.bookmarks-page.grid {
display: grid !important;
grid-template-columns: 1fr var(--sidebar-width) !important;
gap: 20px;
max-width: 100%;
}
/* Force main content to take first column */
.bookmarks-page.grid > main.col-2 {
grid-column: 1 !important;
min-width: 0; /* Prevent grid overflow */
height: calc(100vh - var(--header-clearance) - 50px);
overflow-y: auto;
}
/* Force sidebar to take second column */
.bookmarks-page.grid > div.side-panel.col-1 {
grid-column: 2 !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
background: rgba(var(--bg-rgb), 0.95);
border-radius: var(--card-radius);
border: solid 2px rgba(var(--teal-rgb), 0.85);
padding: 20px;
position: sticky;
top: var(--header-clearance);
max-height: calc(100vh - var(--header-clearance) - 20px);
overflow-y: auto;
width: var(--sidebar-width) !important;
min-width: var(--sidebar-width) !important;
}
/* Make section-header sticky within main */
.section-header {
position: sticky;
top: 0;
z-index: 10;
background: var(--color-bg);
}
/* Section headers in sidebar */
.bookmarks-page.grid div.side-panel h2,
.bookmarks-page.grid div.side-panel h3,
.bookmarks-page.grid .col-1 h2,
.bookmarks-page.grid .col-1 h3 {
color: var(--color-teal);
font-size: var(--font-size-lg);
margin-bottom: var(--unit-4);
margin-top: 0;
}
.bookmarks-page.grid div.side-panel section,
.bookmarks-page.grid .col-1 section {
margin-bottom: var(--unit-8);
}
.bookmarks-page.grid div.side-panel section:last-child,
.bookmarks-page.grid .col-1 section:last-child {
margin-bottom: 0;
}
/* Bundle menu styling */
.bundle-menu {
list-style-type: none;
margin: 0 0 var(--unit-6);
padding: 0;
}
.bundle-menu .bundle-menu-item {
margin: 0;
margin-bottom: var(--unit-2);
}
.bundle-menu .bundle-menu-item a {
border-radius: 15px;
padding: var(--unit-1) var(--unit-2);
color: var(--color-deep);
border: solid 1px rgba(var(--deep-rgb), 0.3);
display: block;
text-decoration: none;
transition: all 0.2s ease-in-out;
font-weight: 500;
}
.bundle-menu .bundle-menu-item a:hover,
.bundle-menu .bundle-menu-item a:focus {
background: rgba(var(--mint-rgb), 0.8);
box-shadow: 0 0 4px rgba(var(--mint-rgb), 0.35);
text-decoration: none;
transform: scale(1.05);
}
.bundle-menu .bundle-menu-item.selected a {
background: var(--color-deep);
color: var(--color-mint);
border-color: var(--color-deep);
}
/* Other grid elements stay as block */
.grid:not(.bookmarks-page) {
display: block;
}
.container {
max-width: 100%;
}
/* Make entire card clickable in bulk edit mode */
ld-bookmark-page.active ul.bookmark-list>li .form-checkbox.bulk-edit-checkbox {
cursor: pointer;
height: var(--bulk-checkbox-height);
left: var(--bulk-checkbox-left);
top: var(--bulk-checkbox-top);
transform: none;
width: 109%;
z-index: 10;
}
a[data-turbo-frame="details-modal"] {
clear: left;
}
/* Card tags */
ul.bookmark-list>li .tags {
margin: 1em 0;
}
ul.bookmark-list>li .tags a:link,
ul.bookmark-list>li .tags a:visited,
ul.bookmark-list>li .tags a:hover,
ul.bookmark-list>li .tags a:focus {
background: var(--color-deep);
border-radius: 15px;
color: var(--color-mint);
font-size: 90%;
padding: 3px 6px;
text-decoration: none;
transition: all 0.1s linear;
}
/* Preview image */
ul.bookmark-list>li .preview-image,
ul.bookmark-list>li .preview-image.placeholder {
border: 0;
border-radius: 0;
margin-top: 0;
background: linear-gradient(0deg, var(--color-mint) 0%, var(--color-deep) 100%);
}
ul.bookmark-list>li .preview-image.placeholder .img {
mask: 0;
background-color: transparent;
}
/* Description */
ul.bookmark-list>li .description {
color: var(--color-desc-text);
margin: 1em 0;
}
ul.bookmark-list>li .description.separate {
-webkit-mask-image: linear-gradient(180deg, #000 60%, transparent);
max-height: var(--desc-collapsed-height);
position: absolute;
top: var(--desc-top-offset);
background: rgba(var(--bg-rgb), 0.7);
padding: 5px;
transition: all 0.2s linear;
white-space: wrap;
}
ul.bookmark-list>li .description.separate:hover {
-webkit-mask-image: linear-gradient(180deg, #000 60%, #000);
max-height: var(--desc-expanded-height);
transition: all 0.3s ease-in-out;
z-index: 11;
}
/* Actions */
ul.bookmark-list>li .actions,
ul.bookmark-list>li .extra-actions {
bottom: 0;
display: block;
left: 0;
position: absolute;
}
ul.bookmark-list>li .actions {
bottom: 0;
height: var(--actions-height);
margin-top: 10px;
padding-top: 10px;
position: absolute;
width: 100%;
}
ul.bookmark-list>li .actions a {
padding: 0 4px;
}
ul.bookmark-list>li .actions button.btn-link {
padding: 0 4px;
border: solid 1px rgba(var(--khaki-rgb), 0.5);
}
.extra-actions {
clear: both;
display: block;
padding-top: 5px;
width: 100%;
}
.actions span {
display: none;
}
.extra-actions .btn {
background: rgba(var(--teal-rgb), 0.5);
}
ul.bookmark-list>li .actions a {
background-color: var(--color-deep);
border-radius: 4px;
color: var(--color-mint);
float: left;
margin: 0 4px 4px 0;
padding: 0 4px;
text-align: center;
width: 50px;
}
ul.bookmark-list>li .actions a:first-of-type {
background: 0;
border: 0;
bottom: 0;
color: var(--color-deep);
margin: 0;
padding: 0 4px 0 0;
position: absolute;
right: 0;
width: auto;
z-index: 10;
}
ul.bookmark-list>li .actions a:hover {
background: var(--color-mint);
color: var(--color-deep) !important;
transition: all 0.1s linear;
}
ul.bookmark-list>li .actions button.btn-link {
background: rgba(var(--danger-rgb), 0.25);
border: solid 1px rgba(var(--danger-rgb), 0.5);
color: var(--color-danger);
opacity: 0.6;
}
ul.bookmark-list>li .actions button.btn-link:hover {
opacity: 1;
transition: all 0.1s linear;
}
ul.bookmark-list>li .actions a:first-of-type:hover {
background-color: transparent;
color: var(--color-mint) !important;
transition: color 0.1s linear;
}
ul.bookmark-list>li .actions .extra-actions button.btn-link {
background: 0;
border: 0;
color: var(--color-mint);
opacity: 0.5;
padding: 0;
}
ul.bookmark-list>li .actions .extra-actions button.btn-link:hover,
ul.bookmark-list>li .actions .extra-actions button.btn-link:focus {
opacity: 1;
}
ul.bookmark-list>li .actions a {
float: left;
}
.actions span.confirmation {
margin-right: 4px;
display: block;
float: left;
}
.actions span.confirmation .btn {
margin: 0 4px;
margin: 0;
position: relative;
visibility: hidden;
width: 22px;
}
.actions span.confirmation .btn::before {
border-radius: 4px;
border: solid 1px;
color: var(--color-mint);
content: "\2713";
display: inline-block;
font-size: 150%;
font-weight: 600;
height: 20px;
left: 0;
padding: 0;
position: absolute;
top: 0;
visibility: visible;
width: 20px;
z-index: 1;
}
.actions span.confirmation .btn.mr-1::before {
color: var(--color-danger-bright);
content: "\00D7";
font-size: 180%;
line-height: 0.65;
}
ul.bookmark-list>li .actions button.btn-link {
float: left;
margin-right: 4px;
}
/* pagination */
.bookmark-pagination.sticky {
background: var(--color-bg);
border: 0px;
margin: 0px;
padding: 0px;
position: absolute;
padding-bottom: 25px;
}
.bookmark-pagination.sticky::before {
background: var(--color-bg);
}
/* notes */
ul.bookmark-list .notes {
background: var(--color-border);
bottom: var(--notes-tab-bottom);
display: block;
height: var(--notes-tab-height);
max-height: 100%;
overflow: hidden;
position: absolute;
right: 0;
width: var(--notes-tab-width);
z-index: 1000;
}
ul.bookmark-list .notes::before {
background: var(--color-border);
border-radius: 4px;
color: #888;
content: "Note";
cursor: pointer;
display: block;
padding: 0 6px;
position: absolute;
right: 0;
top: 1px;
}
ul.bookmark-list .notes:hover {
width: 100%;
height: auto;
}
ul.bookmark-list .notes:hover::before {
display: none;
}
.header-controls {
margin-right: 15px;
}
/* Reduce card height when preview images are disabled/missing */
ul.bookmark-list>li:not(:has(.preview-image)) {
padding: var(--card-padding) !important;
}
/* Adjust title positioning when no preview image */
ul.bookmark-list>li:not(:has(.preview-image)) .title img + a::before {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment