Skip to content

Mastodon Modern by Freeplay

Imported from https://codeberg.org/Freeplay/UserStyles/raw/branch/main/mastodon/modern.user.css

Mirrored from https://codeberg.org/Freeplay/Mastodon-Modern/raw/branch/waf/modern.user.css

Screenshot of Mastodon Modern

Details

AuthorFreeplay

LicenseNo License

CategoryMastodon

Created

Updated

Size80 kB

Statistics

Learn how we calculate statistics in the FAQ.

Failed to fetch stats.

Description

Drastically improves the look & feel of Mastodon. Can be used with other themes that only change colors.

Notes

Source code

Source code has over 10K characters, so we truncated it. You can inspect the full source code on install link.

	// 🦊 BEFORE CLICKING INSTALL:
	// ---------------------------
	// Add your home instance to the "Custom included sites"
	// textbox in the left panel following this format:
	// *://domain.tld/*

	 
/* Update 1.10.3
- Fixed misplaced character count in RTL
- Fix post button being unclickable on long posts on mobile & glitch-soc
*/

/* ==UserStyle==
@name           Mastodon Modern
@version        1.10.3
@description    Drastically improves the look & feel of Mastodon
@homepageURL    https://codeberg.org/Freeplay/Mastodon-Modern
@supportURL     https://codeberg.org/Freeplay/Mastodon-Modern/issues
@preprocessor   stylus

 -- AUTHOR STUFF --
@namespace      Freeplay
@author         Freeplay (https://freeplay.codeberg.page/)
==/UserStyle== */
	 
@-moz-document domain("mastodon.coffee"), domain("socel.net"), domain("brands.town"), domain("mstdn.social"), domain("social.vivaldi.net"), domain("masto.ai"), domain("mastodon.art"), domain("tech.lgbt"), domain("mastodon.social"), domain("mastodon.online"), domain("mastodon.lol"), domain("floss.social"), domain("mas.to"), domain("c.im"), domain("nerdculture.de"), domain("maly.io"), domain("corteximplant.com"), domain("queer.party"), domain("fosstodon.org"), domain("meow.social"), domain("raru.re"), domain("ani.work"), domain("kolektiva.social"), domain("home.social"), domain("mstdn.plus"), domain("mastodon.sdf.org"), domain("toot.community"), domain("sfba.social"), domain("hachyderm.io"), domain("mindly.social"), domain("mastodon.cloud"), domain("bark.lgbt"), domain("wetdry.world"), domain("md.ilyamikcoder.com"), domain("techhub.social"), domain("mastodon.world"), domain("toot.io"), domain("catcatnya.com"), domain("mstdn.constellatory.net") {
/ { // This is just so I can easily collapse everything, shouldn't affect compiled code
	responsiveW1 = 1320px
	responsiveW2 = 1175px
	mobileW = 890px

	transBounce1 = .2s cubic-bezier(0,0,0,1.1)

	statuses-list = ".focusable, .entry, .statuses-grid__item .detailed-status, .trends__item, .story, .account-card, .scrollable :not(.focusable) > .account, .timeline-hint"
	media = ".media-gallery, .video-player, .status-card.horizontal.interactive, .status-card, .audio-player, .picture-in-picture-placeholder"

	/:root {
		--tl-width 750px
		--radius 12px
		--radius-round 24px
		--hover-color rgba(170,170,170, 0.07)
		--elevated-color rgba(150,150,200,0.1)
		--border-color rgba(120,120,200, 0.2)
		--border-color-2 rgba(120,120,120, 1)
		--shadow 0 10px 40px -10px rgba(0,0,0,0.15)
		--shadow-low 0 8px 16px -10px rgba(0,0,0,0.4)
		--shadow-med 0 8px 60px -30px rgba(0,0,0,0.1)
		
		// --accent  // not applied everywhere, just for if you have custom color scheme and want to match it
	}
    
    :not(body):not(.scrollable) {
        &::-webkit-scrollbar {
            width 6px
            margin-block 10px
            &-track {
                background none
            }
            &-thumb {
                border-radius 100px
                transition background-color .2s
            }
        }
        &:not(:hover) {
            &::-webkit-scrollbar-thumb {
                background none
                padding-block 10px
            }
        }
    }
    
	fa() {
		font: normal normal normal 14px/1 FontAwesome;
	}
	compactStatuses() {
		.scrollable:not(.scrollable--flex) {
			padding 0px !important
			padding-bottom 40vh !important
			&::before {
				content ""
				position absolute
				inset 0
				background-color inherit
				z-index -1
			}
			.account-timeline__header, .dismissable-banner {
				margin 0px !important
			}
		}

		{statuses-list} {
			border-radius 0
			&::before {
				border-radius 0 !important
			}
			&::after {
				inset-inline 0 !important
			}
		}
		[class*="explore__"] {
			> * {
				border-radius var(--radius)
			}
		}
		.detailed-status__wrapper {
			margin 0 !important
		}
		.status__action-bar {
			margin-bottom 0px
			gap 0
			margin-inline-end 0 !important
			:not(i):not(.status__action-bar-spacer) {
				display flex
				flex-grow 9999
				justify-content center !important
				max-width 55px
				min-width max-content
			}
			> .icon-button:first-child {
				margin-inline-start -8px !important
			}
		}
		.status__action-bar, .detailed-status__action-bar, .picture-in-picture__footer {
			flex-wrap wrap
		}
		
		{block}
	}

	.rtl {
		textarea {
			text-align right
		}
	}
	a, button, label {
		user-select none
	}
	.button--block {
		font-weight 700
	}
	.unhandled-link, .mention {
		span {
			text-decoration none !important
		}
		&:not(:focus):not(:hover) {
			span {
				text-decoration underline !important
			}
		}
	}
	input, .input-copy, select, textarea,
	.compose-form__upload-thumbnail, .button,
	button:not(.column-header__button), video, .privacy-dropdown__dropdown, .react-toggle-track,
	.reply-indicator, .compose-form__warning {
		border-radius var(--radius) !important
	}
	button, .focusable, a, .media-gallery__item-thumbnail {
		&:focus-visible {
			box-shadow inset 0 0 0 2px #dc7b18
			outline 2px #dc7b18 solid
			outline-offset -2px
		}
	}
	*:not(.radio-button__input):not(input) {
		font-display swap !important
	}
	:not(.radio-button__input):not(span) {
		border-color var(--border-color) !important
	}
	.setting-text {
		padding-inline 10px
	}
	@media (prefers-reduced-motion: no-preference) {
		body:not(.reduce-motion) {
			.load-more, .setting-toggle, .column-header__back-button, .column-back-button,
			.trends__item, .story, .account__avatar, .button,
			.media-gallery__item, .column-link, select, .status-card, .audio-player, .account {
				transition transform .4s cubic-bezier(0,0,0,3), background .2s, opacity .2s !important
				&:active, &:focus-visible {
					transform scale(.99)
					transition transform .4s cubic-bezier(0,0,0,1) !important
				}
			}
			.column-header__button, .column-header__buttons > .column-header__back-button,
			.react-toggle-track, .icon-button, .floating-action-button {
				transition transform .4s cubic-bezier(0,0,0,4) !important
				&:active {
					transform scale(.95)
					transition transform .4s cubic-bezier(0,0,0,1) !important
				}
			}
			.status__content__spoiler-link {
				span {
					display inline-block
					transition transform .4s cubic-bezier(0,0,0,4) !important
				}

				&:active span {
					transition transform .4s cubic-bezier(0,0,0,1) !important
					transform translateY(1px)
				}
			}
		}
		.reduce-motion * {
			animation-duration 0s !important
		}
		
		@keyframes bounceIn {
			0% { transform: scale(1.1); opacity: 0 }
			30% { transform: scale(.99); opacity: 1 }
			60% { transform: scale(1.005); opacity: 1 }
			100% { transform: scale(1); opacity: 1 }
		}

		@keyframes slideUp {
			from { 
				transform translateY(20px) 
			}
		}
		@keyframes slideUpFade {
			from { 
				transform translateY(20px) 
				filter opacity(0)
			}
		}
		@keyframes slideDowFade {
			from {
				transform translateY(-20px)
				filter opacity(0)
			}
		}
		@keyframes slideUpBig {
			from { 
				transform translateY(50vh) 
			}
		}
		@keyframes fadeUp {
			from { 
				transform translateY(10px) 
				opacity 0
			}
		}
		@keyframes scaleIn {
			from {
				transform scale(.98)
				opacity 0
			}
		}
		@keyframes fadeLeft {
			from {
				transform: translateX(20px) opacity(0)
			}
		}
		@keyframes rainbow {
			to {
				filter hue-rotate(360deg)
			}
		}
	}
	.account__avatar, #profile_page_avatar, .account__avatar-composite, .account-card__title__avatar img {
		border-radius 30% !important
	}
	.scrollable,
	.detailed-status__action-bar,
	.column-back-button, .column-header__collapsible.collapsed, .column-header__collapsible-inner,
	.audio-player, .search__input {
		border 0 !important
	}
	.notification__filter-bar,
	.column-header {
		border-inline 0
	}



	.dropdown-menu, .dropdown-animation {
		border-radius var(--radius)
		animation scaleIn .2s cubic-bezier(0,0,0,1.1)
	}
	.dropdown-menu__container__list {
		overflow hidden auto
		border-radius var(--radius)
		max-height 70vh
	}
	.dropdown-menu__item {
		overflow hidden
		a {
			padding .7em 1em !important
			transition background-color .2s, color .2s
			min-width 150px
		}
	}
	.dropdown-menu__separator {
		margin 0 !important
	}
	.interaction-modal {
		border-radius var(--radius)
		overflow-y auto
	}
	.interaction-modal__choices {
		gap 10px
		display flex
		flex-wrap wrap
		.interaction-modal__choices__choice {
			max-height 50vh
			overflow-y auto
			// background-color var(--elevated-color)
			border 1px solid var(--border-color)
			flex 1 0 270px 
			border-radius var(--radius)
			transition background .2s
			position relative
		}
	}
	.compare-history-modal {
		margin-block 20px
	}
	.compare-history-modal__container {
		overflow hidden auto
	}

	.columns-area__panels {
		--top 5px
		gap 0
	}
	@media (min-width responsiveW2) {
		.columns-area__panels {
			padding-inline 10px
			padding-top var(--top)
			box-sizing border-box
			transition padding .4s
			--top 20px
		}
	}
	@media (min-width responsiveW1) {
		.columns-area__panels {
			--top 30px
		}
	}
	
	// EMOJI PICKER
	// This is most likely temporary as the picker may be rewritten or unstylable in a later mastodon update
	.emoji-picker-dropdown__menu {
		border-radius var(--radius)
		overflow hidden
		resize both
		width 400px
	}
	.emoji-mart {
		display flex !important
		flex-direction column !important
		width 100% !important
		height 100% !important
	}
	.emoji-mart-scroll {
		flex-grow 1
		max-height unset !important
	}
	.emoji-mart-bar {
		order 2
	}
	.emoji-mart-category-list {
		overflow visible !important
		display grid
		grid-template-columns repeat(auto-fill, minmax(calc(20px + 6%), 1fr))
		li {
			display contents
		}
		button {
			position relative
			padding 0 !important
			padding-top 100% !important
			img, span {
				height calc(100% - 10px) !important
				width calc(100% - 10px) !important
				inset 5px
				position absolute !important
				transition transform .1s cubic-bezier(0,0,0,1)
			}
			
			&:hover {
				img, span {
					transform scale(1.2)
				}
			}...

Reviews

No reviews yet.