Actions

Work Header

Rating:
Archive Warning:
Fandom:
Additional Tags:
Language:
English
Series:
Part 1 of Site Skins and CSS Quackery
Collections:
References for writing, HTML & CSS stuffs
Stats:
Published:
2022-09-09
Completed:
2025-06-25
Words:
16,365
Chapters:
25/25
Comments:
429
Kudos:
467
Bookmarks:
516
Hits:
22,007

How to Block Tags With Site Skins (And Get Real Specific About It)

Summary:

Just some info I've gathered over the past couple of weeks, about how to:
1. Block tags using Site Skins, block only fics that contain both tag A and tag B, and block fics with a tag that contains a certain phrase, unless they are a specific whitelisted tag
2. Highlight the tags in pretty colors! Or bold, or hide them!
3. Block mega-crossovers with a million different fandoms
4. Select for/block fics that are completed/rated something/have a certain category/don't have summaries
5. Block everything that doesn't have a certain tag, or one of a list of tags
6. Block orphan_account and tag block by author
7. Block only tags of specific types (fandoms, relationships, freeforms, etc.)
8. Block fics focused on original characters, and/or fics without any tags of a specific type
9. Block every pairing with two characters in it—case insensitive, any order, no matter how many other people are also in the tag
10. Block by number of tags

Notes:

If any of this doesn't work correctly, or doesn't cover a specific situation that you'd like it to, please don't hesitate to ask. No guarantees I'll be able to figure it out, but I am rapidly developing an obsession with creating hyper-specific site skin filters, so I'm happy to chew on a problem for a while!

(See the end of the work for other works inspired by this one.)

Chapter 1: has(), not(), and how to chain them together

Chapter Text

Overview

So for a while there actually wasn't a way to filter out tags using site skins. That changed with the rollout of something called the has() selector. It's not available in all browsers, unfortunately, and in some you may have to manually enable it. Permablocking Specific Tags by Eli0t is a great resource for learning how to do that, it's what led me down this rabbithole in the first place. I did my best to explain how the has() selector works before I get into how to chain them together and stuff, but that link will probably do a better job.

(Also, quick disclaimer that while I am studying Computer Science, I have never learned any CSS in a formal way and 100% of what I'm about to write is from some combination of repeating what other people taught me over Ao3, Googling around, and literally just trying stuff to see what happened. So I may horribly butcher terminology and/or do terrible things that make web developers who actually know CSS violently angry at me.)


First and foremost: what is the has() selector and what does it do?

From what I understand, the has() selector is a way of telling your site skin to do something to every element (in this case, fic) that "has" whatever is in the parentheses. In the case of tag blocking, that's a link to that tag's page on Ao3.

*Important note for Firefox users: a lot of these filters rely on the :has() selector, which isn't enabled on Firefox by default. To turn it on, you can go to "about:config" and search for the setting "layout.css.has-selector.enabled". Setting that to true should enable the :has() selector!

First thing's first: if you haven't messed around in the CSS part of the site skins before, you can navigate to it by hitting the "Write Custom CSS" button in the editor, like so:

"Write Custom CSS button"

Now, say you want to select the tag Blorbo Baggins/Steve. First thing you'll want to do is right click on that tag, click "copy URL", and paste it into the CSS part of your site skin.

You should get something like this:

https://archiveofourown.info/tags/Blorbo%20Baggins*s*Steve/works

(Something you'll want to keep in mind is that *s* is used in place of slashes, *a* in place of the & that marks platonic relationships, and %20 in place of spaces in these links.)

Then you're going to want to cut off the "https://archiveofourown.info" part, to get:

/tags/Blorbo%20Baggins*s*Steve/works

Now, you pop it into the has selector, like so:

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])

Once you've got a tag selected, you can do a few things.

This chunk of code will turn the text on all Blorbo/Steve fics blue, which can be super helpful if you want a quick way to make sure your selection is working correctly.

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]) {

  color: blue;

}

While this chunk of code will hide any fic tagged with Blorbo Baggins/Steve:

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]) {

  display: none !important;

}

Or if you really like the ship, you can highlight it with pretty colors in the background like so:

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]) {

  background: linear-gradient(135deg, rgb(199, 199, 255), rgb(240, 160, 210));

}

This highlighting feature is super neat, and I learned about it from Highlight comments of your favourite readers! by ElectricAlice, which also explains how to highlight things with solid colors and even images! I've been using it to highlight authors that I've already bookmarked a bunch of times, so I notice when I run across something new from them in my searches.


More General Filters

Okay. So you can filter out specific tags! But what if, as an example, you don't like any romantic pairings with Blorbo Baggins in them? What do?

See the dollar sign?

.blurb:has(a[href$=""])

If you swap it out with a star, like so:

.blurb:has(a[href*=""])

Then it will filter out any tag that contains whatever you stick in the quotation marks. For instance, if you want to select every single tag (including both the character tag "Blorbo Baggins" and the freeform tag "BAMF Blorbo Baggins") that has Blorbo in it at all, you might do something like this:

.blurb:has(a[href*="Blorbo%20Baggins"])

Or this:

.blurb:has(a[href*="Blorbo"])

(The second one will catch fics whose authors didn't add his last name to their character tag, but you may run the risk of accidentally grabbing fics about his similarly named archnemesis Blorbo Blobbington as well.)

Also, with the way Ao3 ship tags are (usually) formatted, you can get rid of every (correctly tagged) romantic pairing with just two lines:

.blurb:has(a[href*="*s*Blorbo%20Baggins"]),

.blurb:has(a[href*="Blorbo%20Baggins*s*"]) {

  display: none !important;

}

Since we've disallowed tags that contain "/Blorbo Baggins" or "Blorbo Baggins/", it should catch any romantic pairing with him in it.

(It won't, because unfortunately with the way these selectors work, if somebody tagged something "Blorbo Baggins / Steve" you're out of luck unless you also block that tag. But that's pretty rare at least!)


Chained has() Selectors

So this is the part where I went rogue and started messing around. And as it turns out: you can chain the has selectors together!

For example: say you're looking for a romance fic featuring Blorbo Baggins/Steve, but you have very strong opinions about ship dynamics and don't ever want to read anything in that ship with the tag Top Blorbo Baggins. You could filter out "Top Blorbo", but then you would suffer the tragic loss of your second favorite ship dynamic, which is the combination of Blorbo Baggins/Brad and Top Blorbo Baggins.

Fortunately, you don't have to choose! You just have to glue two has() selectors together with a colon like so:

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]):has(a[href*="Top%20Blorbo"]) {

  display: none !important;

}

This will get rid of any of those pesky Top Blorbo/Steve fics, while leaving all the rest for you to read.

As far as I can tell, you can just keep chaining these together. So if you've been incredibly irked by an unbelievably specific combination of 10 or so tags, you can now get rid of it!

This is especially nice because as far as I know there isn't a way to do this using Ao3's search function—you can filter out tags, or include them, but I don't think you can filter out works that have two tags without also blocking works that have only one of them.


The not() Selector

Okay, cool. But suppose you're a Blorbo Baggins/Steve purist. You absolutely do not want to see Blorbo with anyone else, but you can't block all of his relationship tags because then you wouldn't get the pairing you actually want! Is the only option to go through and block every single other ship?

No! There's also another selector called not(), which after some trial and error does actually let you be extremely specific about what you're blocking.

So we start with what we had before, when we wanted to block every ship with Blorbo in it:

.blurb:has(a[href*="*s*Blorbo%20Baggins"]),

.blurb:has(a[href*="Blorbo%20Baggins*s*"]) {

  display: none !important;

}

And the tag we want to allow, Blorbo Baggins/Steve, will go into a not() selector like so:

not(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])

Now it's just a matter of chaining them together like this:

.blurb:has(a[href*="*s*Blorbo%20Baggins"]),

.blurb:has(a[href*="Blorbo%20Baggins*s*"]:not(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])) {

  display: none !important;

}

Note that the first half of the rule can be left alone—Blorbo Baggins comes before Steve alphabetically, so he should be first in the ship tag. But if you want to specifically allow the Steve/Blorbo Baggins tag as well, you can do that the same way, just like this:

.blurb:has(a[href*="*s*Blorbo%20Baggins"]:not(a[href$="/tags/Steve*s*Blorbo%20Baggins/works"])),

.blurb:has(a[href*="Blorbo%20Baggins*s*"]:not(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])) {

  display: none !important;

}

You will unfortunately probably block some fics that are tagged with Blorbo/Steve and similar, but that should hopefully only make you miss out on a handful of fics.

Note: Be careful to put the not() selector inside the parentheses for the has() selector. I tried it the other way around first and it didn't work.

Also: as I understand it, the site skin will check each tag, and will select the fic if any of them satisfy one of your selectors. This means that if a fic is tagged both Blorbo Baggins/Steve and Blorbo Baggins/Brad, it will be filtered—not because of the first tag, but because of the second. So you aren't whitelisting all fics tagged Blorbo Baggins/Steve, but just the tag Blorbo Baggins/Steve. I say this because I've gotten confused about it myself and wound up with weird behavior from my filters. It also foiled my initial attempts to make a whitelisting system that blocks everything that isn't tagged with Blorbo Baggins/Steve, but I might mess around more later to see if I can figure that out.

Edit: After some recent experimenting, the not selectors can also chain together. If you like Blorbo/Steve and Blorbo/Brad but want to filter out all other Blorbo ships, you can double up the whitelisted Blorbo/ tags like so:

.blurb:has(a[href*="Blorbo%20Baggins*s*"]:not(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]):not(a[href$="/tags/Blorbo%20Baggins*s*Brad/works"])) {

  display: none !important;

}

And I need to do a little more testing on this but I'm fairly sure you could exempt, say, poly pairings including both Blorbo and Steve from a filter like so:

.blurb:has(a[href*="Blorbo%20Baggins*s*"]:not(a[href*="Steve"])) {

  display: none !important;

}


The Sad Part (And How To Fix It)

Good news and bad news. The bad news? In my experience (with my specific browser, which is firefox), these tag blockers stop working if you try to put too many of them in your site skin at once. Mine seem to break down after roughly 10-20ish.

The good news? You can get around that (in my specific browser, mileage may vary on this one)! It just involves making a whole lot of small site skins and then adding them as parents of your main one, which is slightly annoying but can lend itself to some nice organization if you're so inclined.

First thing you'll want to do is to create a "face" (at least that's what I've been calling it) that will be your main site skin that you use. Let's say you're me, and you're naming it after the color you made the heading: Indigo. My "Indigo (Face)" site skin doesn't have anything in the CSS window at all, just some colors I put into the wizard to make things look pretty.

Now, I can create a new site skin called Indigo (Blocked Tags). (You could call it "Potato Party" if you want, I'm just using this system because it's a little easier to explain what's going on. Though I did run into problems when I tried to use a parent skin with the & symbol in its name, so you may want to avoid those.)

In the CSS window of my Blocked Tags skin, I can put 10 or so blocked tags and save it. Then I can open up the editor of my Face skin. First, I need to make sure I'm in the CSS view. Then I can scroll down to the very bottom of the CSS window. There should be something called "Advanced" with a "Show" button. (Forgive my janky MS Paint diagrams)

Show Advanced Button

I can click that, and scroll down some more until I get to the tab called "Parent Skins", and click "Add Parent Skin".

Add Parent Skin button

From there I search for my Blocked Tags skin, and add it as a parent. Now, when I'm using my Face skin, it will block all the tags that my Blocked Tags skin does.

These can keep stacking indefinitely, as far as I can tell. So if you're as rabid as I am and you find yourself wanting to block all 50 some-odd synonyms to a tag you hate, let's say "Blorbo Baggins Bashing," you could make a skin called "Blorbo Bashing Filter" and give it 5 parent skins, each blocking 10 of those tag synonyms, and then make that a parent of your Face skin.

This is also useful if you have some tags that you might want to block sometimes, but that you won't necessarily always want to filter out. They can live in their own little site skin, which can be popped on and off of your Face skin at will, depending on how picky you're feeling!

Chapter 2: The .tag Class (and how to highlight/hide specific tags)

Chapter Text

So I've been playing around a bit more, mostly trying to get my hands on a way to filter for "Fic with tag A but not tag B" and getting nowhere. But in the process, I accidentally found some other stuff instead!

Specifically, there's a class called .tag, and you can select them a bit like you might the links from earlier. For example:

 

.tag[href*="Blorbo"]

Will grab all tags that contain "Blorbo" and let you do formatting things to them, without touching the rest of the blurb/fic they are attached to. For instance, you could highlight certain tags—the way I have decided to use this is to put a trans flag gradient on tags with "trans" in them (but not "transphobia," because highlighting that in a giant trans flag feels a little gauche lmao) like so:

 

.tag[href*="Trans"]:not(.tag[href*="phob"]),

.tag[href*="trans"]:not(.tag[href*="phob"]) {

  background: linear-gradient(90deg, rgba(0,249,255,1) 0%, rgba(255,161,254,1) 24%, rgba(255,255,255,1) 49%, rgba(255,161,254,1) 76%, rgba(0,212,255,1) 100%);

}

Or, if you wanted to bold certain trigger tags to make them look like archive warnings, say "Character Death":

 

.tag[href*="Character%20Death"] {

  font-weight: bold;

}

The inverse is also possible. If you want "No Archive Warnings Apply" to not be bolded because you only want bold on warning tags, that would work like so:

 

.tag[href*="No%20Archive%20Warnings%20Apply"] {

  font-weight: normal;

}

You could also use "display: none !important;" from earlier, if for example there are certain tags commonly used as warnings (i.e. Character Death, Horror) that you wanted to hide, because you knew in advance you were down for those things and wanted to be surprised. This would still show a stray comma (possible future project to figure out why/how to get rid of that), but you wouldn't be able to see what the tag used to be. Or if you wanted to be an absolute agent of chaos you could hide ".tag[href*="*s*"]" to hide almost all relationship tags.

Hiding tags doesn't do anything to the fic itself, so it wouldn't be blocked—and from what I understand you should still be able to filter as normal using hidden tags.

I have also learned, belatedly, that .tag[href] seems to be a synonym for a[href], meaning that ".tag[href*="Archive%20Warnings%20Apply"]" and "a[href*="Archive%20Warnings%20Apply"]" mean and do exactly the same thing as far as I can tell.

An Update, now that I have a slightly better idea of what I'm doing:

First off, .tag is a class, or "type", of link. Sort of like how you might have a bunch of different types of screwdrivers—a flathead and a phillips-head are the same in the sense that they're both screwdrivers, but which tool you need is going to depend on the screw. So the ".tag" class helps distinguish between links that are tags and links that are, for example, titles or authors. For our purposes it shouldn't usually matter, or at least the title almost certainly won't, but it is technically possible to get a false positive! For example, if you have a tag filter looking for "cats" and someone's username is "a_trench_coat_full_of_cats". In conclusion: it's a good idea to use .tag if you only want to target tags!

Chapter 3: Blocking Megacrossovers

Chapter Text

Mega-Cross Filter:


ALRIGHT. *Slaps table* I still cannot whitelist tags. But! I figured out how to block mega-crossovers. Nitty gritty (and a bit of belatedly figuring out a pretty major problem) is below, but here's the end result if you'd rather just copy-paste the code (remember to replace the bolded n with the minimum number of crossover tags you want the filter to catch—so if you want to allow up to 3 fandom tags, you would pick n = 4):

.blurb:has(h5.fandoms):has(a.tag:nth-of-type(n)) {

  display: none !important;

}

Edit: further fussing with CSS has led me to a slightly more streamlined version, namely this:

.blurb:has(h5.fandoms > .tag:nth-of-type(n)) {

  display: none !important;

}

It should have the exact same functionality, but with fewer opportunities to misplace a parenthesis!


Okay SO. Please bear with me, my understanding of how CSS works is 20% googling and 80% trial and error. But there's a bit of CSS code, nth-of-type(n), that selects for the nth "sibling" of a class. Using that, we can make a line like this:

(Here we see past me being a sleep-deprived dumbass and not realizing that nth-of-type and nth-child are different things lmao)

a:nth-child(3)

that selects the third link that's the "child" of a given "parent" in the CSS code.

And I also found out by peeking at the page source for Ao3 that the "parent" class of all the fandom tags can be referenced like this:

h5.fandoms

So if you plonk that all together in a couple of has() selectors, you get this:

.blurb:has(h5.fandoms):has(a:nth-child(10)) {

  display: none !important;

}

The number in the nth-child(n) line can be increased or decreased to change how sensitive the filter is—I highly recommend going in with this:

.blurb:has(h5.fandoms):has(a:nth-child(3)) {

  color: blue;

}

to see what gets highlighted for different values of n, so that you can pick a number that's sensitive enough to grab everything you don't want to see while also avoiding THE PROBLEM.

Yeah, so this is the weird part—for some ungodly reason the CSS code also counts the authors and gifts of a fic as "siblings" of the fandom tags. I do not know how or why and if anyone does please tell me so I can try to fix this weird error but. Unfortunately the "n" we're talking about here isn't actually the number of fandoms tagged, it's the number of fandoms tagged + the number of coauthors + the number of users the work was gifted to. So the "crossover filter" will also accidentally catch that one completely innocent fic that happened to have been written by a small army working together to give a gift to another small army. This is fairly rare, so I personally am trying out an n=5 approach just to see how it works, but if you really want to avoid doing that you may want to go with a higher n, or skip this filter altogether.

Edit (yes again): I think I now know why this happens! It comes down to accidentally using nth-child instead of nth-of-type. Basically, the way nth-of-type works is the way that I had expected a filter like this to work. Say we have a parent class with children of two classes, orange circle and purple square. If we try to look for the nth-of-type(2) of the orange circle class:

nth-of-type diagram

We number each child of the class we're looking for, and select the second one. Nice and simple!

nth-child does something similar, but not exactly the same. If we tried to do the same thing by looking for the nth-child(2) of the orange circle class, it would select a completely different element:

nth-child diagram showing a successful selection

Instead of numbering the children of the class we're looking for, we number all of the children regardless of what class they are, and go to the second one. In this case, the second child happens to be the orange circle class, so it is selected, despite being the first child of that class within this parent.

If we instead tried to select the nth-child(2) of the purple square, this happens:

We go to the second child, as before, and it is still the orange circle class. But our filter is looking for a second child that is a purple square, so none of the children of this parent will be selected.

In the case of the fandom tags, the same heading that acts as the parent to those tags also contains links to the author or authors, and any gift recipients. So those will be counted as "nth-children" and inflate the number of fandom tags our filter thinks that a fic has, even though they aren't the class we're trying to look for. nth-of-type solves this problem by behaving the way we expect and only looking for the nth fandom tag.


EDIT: Fixed!

Turns out it needs to use the filter nth-of-type instead of nth-child like I accidentally replaced it with. So we get this instead:

.blurb:has(h5.fandoms):has(a.tag:nth-of-type(n)) {

  display: none !important;

}

And then it stops counting the number of authors and gifts. In completely unrelated news, my adblocker (Ublock Origin) has a neat lil' feature that lets me highlight stuff on a webpage to zap, and I just realized that involves telling me what the css code for something is. So that'll be fun to play with!

Chapter 4: Completeness Filter, Ratings Filter, No-Summary Filter, and more!

Chapter Text

Completeness Filter, Ratings Filter, & More:


On the same little jaunt into view page source, I found that there are specific classes referenced for completed vs. in-progress fics.

To select all completed fics, use the line:

.blurb:has(span.complete-yes)

And to select all incompleted, use:

.blurb:has(span.complete-no)

It's pretty easy to filter by completed as is, but if you wanted to apply different backgrounds to each so that you could tell at a glance which was which, this makes that possible!


There are also ratings filters! Explicit is the example I'll use, but the rest are like so: rating-general-audience, rating-teen, rating-mature, and rating-notrated which bucks the dashes-as-spaces convention for some reason.

.blurb:has(span.rating-explicit)


Wait! But why does this matter if Ao3 already allows filtering for these things?

And to that I say: chain them with tag selectors.

Like a ship but don't want any E-rated fics of it?

.blurb:has(span.rating-explicit):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])

Boom. Gone.

Only want to read Angst with a Happy Ending if the happy ending is already there?

.blurb:has(span.complete-no):has(a[href$="/tags/Angst%20with%20a%20Happy%20Ending/works"])

Done.

Have a ship that you don't mind if it's not the focus, but don't otherwise want to see?

(Using M/M for the Blorbo/Steve example, but the other categories are category-none, category-gen, category-femslash, category-other, category-multi, and category-het)

(Also fair warning that anything tagged with multiple categories will be sorted under category-multi for filtering purposes)

.blurb:has(span.category-slash):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])

It's an option! One with a fair amount of false-positives and false-negatives, but it does exist lol!


There's a ton of these, it turns out. This will select anything that's part of a series:

.blurb:has(ul.series)

And this will select anything that doesn't have a summary:

.blurb:has(ul.required-tags):not(:has(blockquote))

(That first bit is important for reasons I'll get to in the next chapter)

...and it occurs to me that I might have just accidentally figured out the tag whitelisting problem.

welp

more on that in a sec!

Chapter 5: Tag Whitelisting! Filter Tags Unless that Fic Has Another Tag!

Chapter Text

Tag Whitelisting! Filter Tags Unless that Fic Has Another Tag!


So, turns out it's actually way less complicated than I thought it was to implement the tag whitelisting! Basically, if you take a not selector and shove a has selector in it, like so:

.blurb:not(:has(a[href$="/tags/Blorbo%20Baggins/works"]))

You get a whitelist! So this will select every fic that is not tagged with Blorbo Baggins...

Except that's not actually quite true. It will select every blurb that is not tagged with Blorbo Baggins.

Comments are blurbs. Site Skins are blurbs. Many things we do not want to uniformly filter out are blurbs. (I discovered this when I went to swap out of my testing skin and realized OOPS they're all blue now.

Hence this addition:

.blurb:has(ul.required-tags)

Every fic has to have the required tags, so this should select only for blurbs that are fics, not things like site skins and comments that can't be tagged with anything.

Or if you want to restrict the whitelisting to a certain fandom (say in fandom My Fandom you want to make sure Blorbo Baggins is tagged, but other fandoms probably won't ever tag him so you'd rather leave those alone.

.blurb:has(a[href$="/tags/My%20Fandom/works"])

Now we don't need the required-tags filter, since only fics should get tagged with a fandom. Chain them together like so:

.blurb:has(a[href$="/tags/My%20Fandom/works"]):not(:has(a[href$="/tags/Blorbo%20Baggins/works"]))

And then just keep adding on not() selectors as you like. (Note that a fic only needs to have one of the tags in this list to be spared from the purge.)

.blurb:has(a[href$="/tags/My%20Fandom/works"]):not(:has(a[href$="/tags/Blorbo%20Baggins/works"])):not(:has(a[href$="/tags/Steve/works"])) {

  display: none !important;

}

And there we go!


There's also another fun application of this sort of formatting, which is FINALLY the ability to filter out a tag unless it is accompanied by another tag.

So say you completely refuse to engage with any Blorbo/Steve works that are not Fluff. They were sad enough in canon, damn it! Beholde:

.blurb:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]):not(:has(a[href*="Fluff"])) {

  display: none !important;

}

(The ul.required-tags filter isn't necessary here because only fics are going to be tagged blorbo/steve, so we don't have to worry about the Oops All My Site Skins Are Gone problem this time)

I am inordinately excited about this because I've been trying to do this for AGES because I have UNMANAGEABLY SPECIFIC preferences when it comes to certain tags and now FINALLY here it is. It works!!!

Chapter 6: Oh hey, orphan_account has an id number! Also, tag blocking by author

Chapter Text

So uh, turns out orphan_account has an id number just like a normal user would! Meaning you can block and/or do custom formatting things to orphaned works like so:

.user-9 {

  display: none !important;

}

Unfortunately the same is not true for "anonymous," I'm guessing because those still have the user id of the original author and it's just hidden/not in use.

EDIT: This tutorial by Eli0t will show you how to select for anonymous fics!

But if anyone needs to retaliate against a sudden influx of Blorbo/Steve spitefics that are orphaned and thus impossible to block by user, like so:

.user-9:has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]) {

  display: none !important;

}

Or block specifically explicit works by orphan_account since those do tend to have a higher proportion of dead dove fics:

.user-9:has(span.rating-explicit) {

  display: none !important;

}

This same format also works for any user, so if there's a particular author you really like who happens to write a lot for a tag or ship that you don't, that's blockable in the same way.

(Can you tell I'm a lunatic who never uses the built-in tag filtering system and just lets everything wind up in a massive pile to be handled by my site skin? because I am.)

Chapter 7: Blocking tags of a specific type (including fandom tags)

Chapter Text

Blocking tags of only a specific type


More on how this came about below, but for anyone who just wants to plug and play, you can create a type-specific tag filter like so:

.blurb:has(.type > .tag[href*="Banned%20Phrase"]) {
  display: none !important;
}

Where .type is replaced by what type of tag you want to block:

.fandoms for fandom tags

.warnings for archive warnings

.relationships for relationship tags

.characters for character tags

.freeforms for freeform tags

And Banned%20Phrase is replaced by whatever you want to filter out. As with the normal tag filters, spaces get replaced with "%20", slashes with "*s*", and & signs with "*a*"

With this filter, any fic with a tag of the specific type you're filtering that contains the banned phrase won't be shown.


So this came about purely because I wanted to be able to block fandoms that I'm not in or don't know about, and thus be able to look at crossovers without either picking a specific crossover fandom beforehand or getting mostly stuff where I don't know half the source material. Blocking fandom tags is basically the same as blocking any other tag—except that I encountered a problem.

Say you don't know much about the Batman franchise so you want to block it. There's a lot of different fandoms included in that, from cartoons to movies to comics, and you could grab all of them at once in a filter like so:

.blurb:has(a[href*="Batman"]) {
  display: none !important;
}

What if somebody tagged a crossover fic that is in fandoms I know with something like "Blorbo Baggins thinks he's Batman"? This filter would catch and block a fic based on that tag. I could fix this problem by finding and filtering every single individual fandom tag with Batman in it, but I can say from experience that doing this is very annoying.

To get around the problem, we just tell the filter to only focus on those links if they happen to be the child of a particular class, in this case the "fandoms" class.

(There's a little more fiddling as well, specifically using .tag instead of a, though I'm not 100% sure if that's actually necessary because I kept running into errors while testing this even though my code was actually working fine! It turns out literally just using href*="t" as a filter is a tremendously bad idea, even if you're only trying to test if a specific way of filtering works, because the letter t is in literally every tag. Every tag's url contains the phrase "/tags/". So uh. Don't try to block that lmao.)

Anyways, the filter I came up with is this:

.blurb:has(.fandoms > .tag[href*="Batman"]) {
  display: none !important;
}


For a related issue, what if there's a character, let's call him Brad, who's like... fine. I don't mind him being present in a story, but I'm not very interested in him, and I don't want to read a fic that focuses on him. I could block every fic that tags him, but that will catch ones where he's only present in the background, and some of those might have really appealed to me! A proxy I've found that I actually quite like is that if you block every relationship tag that includes a character, it tends to catch only ones where that character is actually getting focus (and if you restrict it only to fics that tag both Brad and a relationship with Brad in it, then you're really focusing in on fics where he's playing a medium-to-major role).

This came up in the first chapter, and it can be done by blocking both "/Brad" and "Brad/", and I guess also "Brad & " and " & Brad", but again that's super annoying. It involves creating four separate filters for just one thing, and it misses things like "Brad / Steve" or "Steve x Brad", and if your browser is anything like mine, it gets grumpy when you put too many tag filters in one site skin, so a poor fool might wind up with an entire skin solely dedicated to filters designed to block out one character's relationship tags. (It's me. I'm the poor fool.)

Longwinded way of saying, hey! Just make it so the filter of the characters name only applies to relationship tags!

.blurb:has(.relationships > .tag[href*="Brad"]) {
  display: none !important;
}

Dunno how many people have this specific problem like I do, but this is about to save me literally an entire site skin so. I'm pretty happy about it!

Chapter 8: Blocking fics focused on Original Characters

Chapter Text

Alright. So I was tag-blocking Original Characters for a while, when I happened to notice that some of my bookmarks were getting blocked. Obviously those are stories that I liked, and something was going wrong with my filters. I looked into it and, welp, some of them had minor original characters tagged. What do?

Well, I could allow tags like "minor original character," and if the bookmarked fics I want to un-block have non-canonical tags, I could exempt the specific tag "technically an oc but he's just there to die and set the stakes" from my filter and fix the problem that way. But like, I don't actually dislike original characters. I just don't generally read fics that are focused on them, so I set up a somewhat overaggressive filter and hoped for the best.

Anyways, I decided that I'd rather scroll past things than miss things, so I altered the OC filter to allow original characters in general, but filter tags like "OC focused" or relationship tags with original characters in them. Problem solved?

Haha, nope. Obviously everyone tags a bit differently so no filter will be perfect, but I started poking around in a fandom outside my most usual stomping grounds where there's a lot more OC-focused content, and realized my newly renovated filter was now very underaggressive. So I decided to try and shore it up with a filter that zaps fics where all of the characters tagged are OCs. Here it is:

.blurb:has(ul.required-tags):not(:has(.characters > .tag:not([href*="riginal"]):not([href*="OC"]):not([href*="canon"]):not([href*="Canon"]))) {
  display: none !important;
}

So! To break this down, our friend from a previous chapter, ul.required-tags, is back so that I don't accidentally hide all my site skins again. Because that would be embarrassing and definitely didn't almost happen, nope, no sir.

What the rest of this whole thing is basically saying is, grab everything that does not have a tag that is not one of this list of tags. "riginal" is just leaving off the O at the beginning, since these selectors are case sensitive and I don't want to have two separate clauses for "Original" and "original". Then I also added "canon" and "Canon" to catch tags like, "The canon characters make guest appearances" and such.

Some flaws with this filtering system include: If the author has the OC tagged by name, the filter doesn't know a canon character from a hole in the ground so it won't catch that. There's also tags like "oc" or "Person's Name - oc" and whatnot, which will be left out because of the case sensitivity. They could be included, but just grabbing "oc" will have a lot of false positives if there's a character named something like, idk, "Doc Brown", and I can't be bothered to figure out absolutely every iteration when that type of tag is fairly rare anyway.

(On a related note, if you want to use this for a fandom with a sentient supercomputer character called "OCTOPUS", you may wish to remove the "OC" clause from the filter.)


A side-effect that I'm not sure how to fix and honestly kind of like: the way this is structured means that it will catch any fic not tagged with a character besides the one on the mini-blacklist there, including fics that aren't tagged with any characters at all. There's actually a way to generalize this function:

.blurb:has(ul.required-tags):not(:has(.type > .tag) {
  display: none !important;
}

will catch any fic that doesn't have any tags in the specified category, once .type is replaced with that category. As before, those are:

.relationships for relationship tags

.characters for character tags

.freeforms for freeform tags

(There's also fandom and warning tags, but every fic has to have at least one of each so they aren't super useful for this filter.)

This allows for a little filter I like to call "I have no idea what's going on here":

.blurb:has(ul.required-tags):not(:has(.freeforms > .tag)):not(:has(blockquote)) {
  display: none !important;
}

which catches fics with no summary and no freeform tags.

Chapter 9: Case insensitive filters! Search for multiple phrases in a tag!

Chapter Text

Okay so—you know that stuff I said about how "Blorbo Baggins/Steve" and "Steve/Blorbo Baggins" show up as completely different tags and there's really no way to combine them?

TURNS OUT I WAS WRONG!

Beholde:

.blurb:has(a[href*="*s*"][href*="Blorbo%20Baggins"][href*="Steve"]) {
  display: none !important;
}

You can, as it turns out, just straight-up squish the square bracket hrefs together like this to look for a link that matches all of them. And that just. Works. IT JUST WORKS. How did I learn this? I just fuckin' tried it and it worked it was literally trial and error, I have looked at so many how-tos about CSS links trying to find something like this and got NOTHING and then I just MASHED THINGS TOGETHER AND IT WORKED. why is css like this.

To explain why I'm losing my mind here—if you're trying to block every fic where two specific characters are shipped together, this will get rid of 1. The canonical tag, 2. The canonical tag but flipped ("Steve/Blorbo"), 3. The canonical tag but there's spaces around the slash ("Blorbo / Steve"), and 4. every single poly pairing with those two in it. Which saves a whole lot of frustration trying to block ten different OT3s combining the ship you're trying to block with different characters.

This is also really useful for trying to block, shall we say, salt or character bashing, which is normally really difficult because what you're trying to target is usually the long rambly tags that aren't in any kind of canonical form. But you could nab, "I hate Blorbo Baggins", "People are gonna call me a Blorbo hater but whatever", and "If you don't hate that stupid Blorbo character don't talk to me" all with the same filter:

.blurb:has(a[href*="hate"][href*="Blorbo"]) {
  display: none !important;
}

In general, this makes blocking via chatty non-canonical freeforms way easier, since it's a lot more flexible to search for a whole list of keywords than just a single phrase.

Also, there's just. There's just a case insensitivity flag that it took me like three months to find out about? It's just casually been around since like 2014??? You literally just shove an "i" in the href, inside the square brackets like so:

a[href*="blorbo%20baggins" i]

So to catch... I think almost every single iteration of a particular ship, barring misspellings of the names:

.blurb:has(a[href*="*s*"][href*="Blorbo" i][href*="Steve" i],a[href*="x" i][href*="Blorbo" i][href*="Steve" i]) {
  display: none !important;
}

That'll get "Blorbo Baggins/Steve", "Steve/Blorbo", "Blorbo Baggins/Brad/Steve", "blorbo x steve", "Steve X BlorBo", you name it.

And since I don't think I've gone into this yet—you can plop multiple links into has() and not() selectors, separated by commas like so: ":has(a[href*="tag1"],a[href*="tag2"])" which will grab anything that has any of the listed tags (or anything that is not any of the listed tags, if it's a not() selector). This doesn't open up any new possibilities really but it does make everything way cleaner lmao

Chapter 10: Block by number of tags

Chapter Text

So this is a bit of an extension of the megacrossovers thing, and it's also going to be very short because I have tried. So hard. To duplicate that for other types of tags—so like, a filter that can take a minimum or maximum number of relationship tags, or freeforms, or characters, and block based on that. But I don't think the way the html for Ao3 is written supports doing that.

(Basically, that filter relies on all the tags of a certain type being clustered together in the same "box", but Ao3 keeps each individual relationship or freeform tag in its own "box" by itself for some reason.)

But it is possible to target the number of tags, just straight-up. This includes warnings, relationships, characters, and freeforms, all in one big mess. So if you want to block fics that have, ah. Too many tags, for some purely hypothetical reason, you should be able to do it like this:

.blurb:has(li:has(.tag):nth-of-type(n)) {
  display: none !important;
}

where n is the number of tags that should be blocked. So if you wanted to allow fics with 30 tags, but no more, you would use n = 31.

Similar deal if you want to block fics with too few tags:

.blurb:not(:has(li:has(.tag):nth-of-type(n))) {
  display: none !important;
}

where n is the minimum number of tags for a fic to not get blocked, i.e. if you wanted them to all have at least 5 tags, you would use n = 5.

You can get an okay-ish ballpark estimate for relationship tags—the only tags that come before those are archive warnings, and there's usually only one or two of those, and only up to five, to fuck up the count. So in theory if you wanted to allow about n relationship tags, plus or minus a couple, then you could do this:

.blurb:has(li.relationships:nth-of-type(n)) {
  display: none !important;
}

This time, if you wanted to block at about 10 relationship tags n should be... eehhhh about like 11 or 12 probably, since you know you're getting one warning tag and that's the most common number of them by a country mile.

Chapter 11: Block by summary length

Chapter Text

This is getting very niche, and it was already pretty niche to start with, but it mostly just fascinates me that this is possible—you can block fics by the length of the summary. Not in words or anything, but in paragraphs, like so:

.blurb:has(.summary.userstuff > p:nth-of-type(n)) {
  display: none !important;
}

So you can block anything with a summary longer than, say, 10 paragraphs, by setting n = 11.

I'm not sure if Ao3 has a limit for how long summaries can be? I've definitely never run into it before, but if they don't and there's an Incident with a troll fic forcing people to scroll past the entire script of the bee movie every couple of days, then uh. I guess we'll be prepared?

Chapter 12: Pictographic tags

Chapter Text

I may well be the only person alive who wants this BUT. Here goes anyway.

Recently I've started replacing a bunch of ship tags in a fandom I frequent with images, because 1. they are pretty, 2. I think I recognize them faster than the written versions now that I'm used to them, 3. I can, and 4. deep down I'm just Like This.

So if I want to use an image found at "https://some-cool-image-idk.jpg" for the tag Blorbo/Steve, I would use this code:

.relationships > .tag[href$="/tags/Blorbo%20Baggins*s*Steve/works"],
.relationships > .tag[href$="/tags/Blorbo%20Baggins*s*Steve/works"] {
  background: url("https://some-cool-image-idk.jpg") 50% 50%;
  background-size: cover;
  color: transparent;
}

Be careful! that the image you're using is hosted on a secure website. You should see the little padlock thingy to the left of the url you're currently on be closed, when you visit "https://some-cool-image-idk.jpg", or whatever the equivalent is for your browser. I ran into problems when I first started doing this, because one of the images I tried to use wasn't secure and having the site skin connect to it created a security flaw on Ao3. Long story short, keep to websites you trust!

You can add one of these blocks of code for each tag you want to turn into an image!

To break down what the filter actually does, the .tag and .tag:hover are both there so that the image won't disappear once the cursor hovers over the tag, since "links" and "links that I'm hovering over" are separate objects to CSS (this lets you do fun little effects in webpages when a user hovers over a link).

.relationships > .tag makes sure the tag is the child of ".relationships" (basically, makes sure it's a specific type of tag) You should also be able to use ".freeforms > .tag" to select only freeform tags, ".characters > .tag" for character tags, and just ".tag" for any tag at all.

The background: url("blahblahblah") part sets the background to be the desired image.

The 50% 50% part that comes right after the url is about the placement of the image. This placement centers it—but since tags are long skinny rectangles and most images are not, very likely only a thin sliver of your image will be displayed. You can adjust that by fiddling with the second 50%, which is what controls height. So if you want the very top part of an image, you would use 50% 0% instead, and if you want something near-ish the bottom, you'd go with 50% 90%. Because both I and everything I do is extremely janky, I have been figuring this out for each tag purely by trial and error.

"background-size: cover;" just resizes the image to fill the entire tag.

And "color; transparent;" is the part that hides the text completely! A more sensible person might choose images that are fairly monochromatic and then pick the color to contrast against that and make it visible. I did not do that.

What I did do was add some more code that makes the text appear when you hover over the tag!

.relationships > .tag:hover {
  color: black !important;
  text-shadow: 1px 0 #fff, -1px 0 #fff, 0 1px #fff, 0 -1px #fff;
}

"color: black !important;" forces the text to be black.

Then, since a significant number of the images I use contain both dark and light bits, which is a terrible idea if you're trying to choose a background to put text on, I also added the "text-shadow" part, which creates a small white border around the text. This makes it... at least more legible, even if the image itself is a complete nightmare of contrast.

So little black-and-white bubble letters pop up when I mouse over the tag images, just in case I've forgotten what one of the images means. This code will affect all relationship tags, so it doesn't need to be added for every new ship that gets an image representation. As with the first filter, you can swap ".relationship >" out with a different "type" of tag, or delete it altogether, to have the filter apply to freeforms/characters/all tags.

Is any of this practical? Hell no! But I find it fun, and maybe someone else will too. Because why have a perfectly legible "Fluff" tag when you could put a picture of a mug of hot cocoa instead?

Chapter 13: Public bookmark warning system

Chapter Text

Edit: Eli0t recently pointed out that there's a much more efficient way to do this! Your own bookmarks all have a link to your bookmarks page buried in there, so you can select for thosemuch more easily.

Edit2: I've also been warned by a commenter that my code from before doesn't highlight a bookmark that is a rec but not public, which can be a good thing if you want to leave all your recommendations public by default, but not so much if you clicked the wrong checkbox by accident!

To highlight all public bookmarks, including recs, we make sure we look for bookmarks with both "span.public" and "span.rec":

.blurb:has(span.public,
span.rec):has(a[href*="/users/USERNAME/pseuds/USERNAME/bookmarks"]) {
  background: red !important;
}

("span.public" and "span.rec" correspond to the icons in the upper right corner of a bookmark, either the blue square with the corner folded down that is on normal public bookmarks, and also the blue heart that is on recs. If a bookmark is both a rec and also private, it will have the padlock icon of a private bookmark, so this filter will leave it be.)

Or, if you want to include a tag for intentionally public bookmarks that shouldn't trigger the warning:

.blurb:has(a[href*="/users/USERNAME/pseuds/USERNAME/bookmarks"]):not(:has(span.private,
a[href$="/tags/PublicOnPurposeTag/bookmarks"])) {
  background: red !important;
}

(This one uses a slightly different method for highlighting both normal public bookmarks and recs. It just looks for bookmarks that don't have the little padlock icon, instead of looking for ones that do have the bookmark icon or the heart icon. Both should function in exactly the same way, this one just looks a little neater when combined with the tag whitelist.)

And to leave recs public by default, feel free to use this code from before:

.blurb:has(span.public):has(a[href*="/users/USERNAME/pseuds/USERNAME/bookmarks"]) {
  background: red !important;
}

Last but not least, it occurs to me that it's a good idea to point out that you can make these filters look at the tags on a work as well. You know. If you happen to only mind a bookmark being public by accident if it has certain tags on it. For some reason :P

.blurb:has(a[href*="/users/USERNAME/pseuds/USERNAME/bookmarks"]):has(a[href$="/tags/TurnRedTag/works"]):not(:has(span.private)) {
  background: red !important;
}

That's mostly it, but if you want to laugh at my janky first attempt at this, feel free to keep reading below the cut lol!


This is a bit of an obscure one, but here goes!

Personally I'm the type to keep my bookmarks private, mostly because my body is merely a vessel for social anxiety and the less eyes on anything I do the better, but of course Ao3 defaults to making a public bookmark. And despite knowing that it doesn't matter and nobody actually cares, I do get anxious about accidentally leaving things public when I didn't mean to. So I made this!

.bookmark > .blurb:has(span.public):not(.short) {
  background: red !important;
}

Basically, it's some CSS code that can be put into a site skin to make it highlight public bookmarks in bright red. So as soon as I make a bookmark, if I did forget to private it my screen immediately turns the color of a stop sign and I can fix it quickly without freaking myself out.

Edit: Since first posting this I tweaked the code to add the !important flag onto the background. This makes it so that the red coloring gets prioritized over other CSS code—so if you happen to have other skins that change the backgrounds of your bookmarks, those won't hide the warning.

This ran into some issues along the way—mostly related to highlighting things it isn't supposed to, like the list of people who've bookmarked something that comes up when you click the number of bookmarks on a work (which is fixed by adding :not(.short)), and the list of recent bookmarks on people's dashboards (which is fixed by adding .bookmark > before the blurb).

But the major one that I haven't figured out how to fix entirely is that, well, it turns the background of any public bookmark bright red. This includes other people's. This can be mostly fixed by tweaking the code to use your own user ID. So using mine as an example:

.bookmark > .user-3298668:has(span.public):not(.short) {
  background: red !important;
}

This will only highlight bookmarks that are tied to your user ID. (Well, in this case my user ID, you'd want to replace the bolded number with yours.) This includes anything you've bookmarked, but also anything you've published—the classes attached to bookmarks on Ao3 don't seem to make any distinction between the author and the person who marked it. So your own works will turn up in bright red in other people's bookmark lists. I don't think that can really be fixed, or at least I haven't made any progress on that front.

Another obvious issue with this: what if you want to have some public bookmarks, or like to have most of your bookmarks public but keep a few private? That's actually pretty easy to fix by adding a tag filter like so:

.bookmark > .user-3298668:has(span.public):not(.short):not(:has(a[href$="/tags/TAG/bookmarks"])) {
  background: red !important;
}

Replace the bolded TAG with whatever tag you'd like to use to indicate to your site skin that it's okay, this one was left public on purpose and shouldn't be highlighted, i.e. "public" or "visible", or something like "purple%20monkey" if you want to confuse the hell out of anyone who looks at your bookmarks. Just keep in mind that authors can see the tags you put on their works!

I haven't personally tried this, but it should also be possible to add multiple exception tags, i.e.

.bookmark > .user-3298668:has(span.public):not(.short):not(:has(a[href$="/tags/TAG1/bookmarks"])):not(:has(a[href$="/tags/TAG2/bookmarks"]))

Just in case you want to have multiple categories of public bookmark tags.

Chapter 14: Misc has() selector applications, including blocking series

Chapter Text

So I happened across a post on reddit recently where someone was trying to block series using site skins, and since I actually do that a lot in my own skins I figured I'd put a quick tutorial for it here! Plus a bunch of other miscellaneous applications for the has() selector besides tag blocking, like blocking works that are gifts for a specific user and stuff like that. Basically I just combed through the blurbs for useful-looking links and wrote up whatever I found lol

 

Series Blocking:

Every work in a series should have a link back to the page for that series. If you copy that link, you should get something like "https://archiveofourown.info/series/2340623" (using one of mine as an example), which lets you block every work in that series like this:

.blurb:has(a[href$="/series/2340623"]) {
  display: none !important;
}

You can also add tag blocking on top of that, if you so desire:

.blurb:has(a[href$="/series/2340623"]):has(a[href*="tagtoblock"]) {
  display: none !important;
}

which will only block works in that series which have a specific tag.

 

Select by Gifts:

Same deal, we use the link to the person's gift page to select every fic that's been gifted to them:

.blurb:has(a[href$="/users/Username/gifts"])

This can be good for when there's somebody in your fandom who does a lot of gift exchanges and has very different preferences from you as far as character or ship dynamics, or if there's a user who has very similar preferences to you and you want to highlight their gift fics because you're more likely to enjoy them.

 

Oneshot Selector:

There's a link to specific chapters in the blurbs for fics with more than one of them, and combined with the completeness filter from earlier we can do this:

.blurb:has(span.complete-yes):not(:has(a[href*="/chapters/"]))

to select for completed fics with exactly one chapter!

 

Select for Kudosed/Bookmarked/Commented/Collected Fics:

We can't do anything based on the number of kudos/bookmarks/etc. on a fic, but it is actually possible to select for fics that have at least one since those have extra links.

For kudos, we can use this:

.blurb:has(a[href$="#kudos"])

or this, to select for no kudos:

.blurb:has(ul.required-tags):not(:has(a[href$="#kudos"]))

For bookmarks, same thing except we replace "#kudos" with "/bookmarks", like so:

.blurb:has(a[href$="/bookmarks"])

And then for comments we'd use "#comments",

And "/collections" for fics that have been put into at least one collection.

Probably not going to use this personally since my general ethos for browsing is "put literally every fic that's been updated since I last checked in a giant pile, exclude only what I know I'm not interested in, and then scroll through everything" and this isn't very useful for that. And tbh the archive filtering system is probably better for this function anyway since it lets you pick a number lmao. But it's an option that exists! And it might be more useful for highlights and the like, i.e. "I really like this ultra rarepair and I want to put a giant bold outline around fics tagged with it that have been bookmarked"

 

Select by Number of Authors:

I honestly have no idea what this would be useful for, but I did manage to make a filter that seems to select for how many authors a fic has like this:

.blurb:has(a[rel=author]:nth-of-type(n))

where in this case n should be the minimum number of authors you want to select, plus one—so if you want to select every fic with two or more authors, you'd pick n=3. (If this seems weird that's because it is, the title also counts toward that number even though it's not an author, because it's still a link.)

Chapter 15: Making filters ignore your bookmarks

Chapter Text

So I just got a question about whitelisting bookmarks, and it occurred to me that accidentally disappearing some of mine has been a backburner worry for me for a while and I should probably do something to fix that!

Fortunately, every fic on your bookmarks page also has a link to your bookmark page, which should end like this: "/pseuds/yourPseud/bookmarks", and we can use that to tell our site skins to leave them alone.

There are two options here. Option the first is changing every filter to exclude bookmarked fics, like so:

.blurb:has(a[href*="filteredTag"]):not(:has(a[href$="/pseuds/yourPseud/bookmarks"])) {
  display: none !important;
}

Which is nice but also a bit annoying if, like me, you have probably over a hundred of these fucking things lmao. So instead we can go back in and unblock all the fics in our bookmarks like this:

.blurb:has(a[href$="/pseuds/yourPseud/bookmarks"]) {
  display: block !important;
}

("display: block" is, as far as I can tell by trial and error, how fics are normally displayed when we don't hide them with "display: none")

The thing about this is that, unlike most filters, this one is going to be kind of 'competing' with the rest of them—it's trying to apply "block" to a fic, and another filter is trying to apply "none". So we want to make sure that this whitelisting filter gets to 'win', which we do by putting it last. This means going in the skin you're currently using, not in any of the parents, and putting it after any filtering code you might have. That's because as far as I can tell, CSS does each block of code one at a time, and later blocks override the earlier ones.

If you're having trouble, then making a new skin with just this bookmark whitelisting code, giving it your old skin as a parent, and using the new skin instead should work.

Edit: Whoops! Turns out I am a naive fool for ever imagining CSS might work so sensibly. Actually, it decides priority based on specificity first, and then on how close to the end of the code it is. A clause gets a specificity rating. From what I've read I'm pretty sure it involves COUNTING THE DIFFERENT OBJECTS AND CLASSES REFERENCED AND TALLYING UP A SCORE. Because this godforsaken coding language was designed to give me ulcers. Anyways, that means that in order to make absolutely sure your bookmark whitelisting code is getting prioritized first, it may be useful to purposefully make an obnoxiously overspecific filter like this one:

li.blurb:has(h5.byline > a[href$="/pseuds/yourPseud/bookmarks"][href$="/bookmarks"][href$="bookmarks"][href$="ookmarks"][href$="okmarks"])[id*="bookmark_"] {
  display: block !important;
}

Do most of those do exactly the same thing? Yes. Are they completely pointless except to tell the CSS code "Hey look this filter is really specific and you should apply it first! :D"? Also yes. Is this probably a horrifying abomination that would give any web developer nightmares? Oh, absolutely. But! It did work for me when some of my filters were getting prioritized over the old whitelist no matter where I put it. So it's worth a shot if you're still having issues after moving your whitelist around a bunch. And, in total seriousness: if this still doesn't work, it is genuinely worth trying to add another 10 [href$="ookmarks"] just to see if that does the trick. There is a nonzero chance that will help, and knowing that will haunt me for the rest of my life ;-;

(I think actual best practices for stuff like this in CSS probably involves just. Not having multiple filters competing with one another like this. But here we are!)

Incidentally stuff like this is probably what the "!important" flag is usually for, but I'm a bit paranoid that removing it might make the filters stop working in unpredictable places, in case there are other formatting rules floating around that might compete with it.

Edit the 2nd, some years later: Upon further shock testing (aka I switched my site skins to this system and it's worked fine), filtering generally doesn't seem to need the !important flag in order to function (or at least I've never run into an issue where it does). Therefore it is much, much easier to just use "display: none;" in one's filters and then give the bookmark whitelist the !important flag.

Another fun trick that I've been playing with is to add aesthetic changes to my filters, such as fancy borders like this:

  border-style: dashed;
  border-width: medium;
  border-color: darkblue;
  display: none;

There's a guide here that I found useful on different things you can do to the borders, and the same site has a lot of good info on various styling options! Now, most of the time you will not see this at all, but it does make it a lot more obvious when you're looking through your bookmarks that some of them would be blocked by your filters (which at least in my case is often a sign that one of them is a little too aggressive). And if you're like me and you have, again, truly way too goddamn many of these, then you can HYPOTHETICALLY color-code them so that you will HYPOTHETICALLY have slightly more of a hope of figuring out which one is responsible for hiding a completely nonoffensive fic. i definitely didn't have to look up how to do like, dashed vs. solid borders because i have so many of these and have been so confused that i ran out of colors. not at all. don't look at me.

All that said, this will only unhide your bookmarks when you're looking at them from your bookmarks page, which is where the link that we used for the whitelist shows up. So if you're just browsing a tag or a fandom, fics that you've bookmarked will still be hidden in that view. But it should make it so that once you look through your bookmarks specifically, none of your filters will be applied.

Chapter 16: is() and making the filters a little neater

Chapter Text

Just ran across a helpful selector while answering a question, and I thought I'd give it its own section! It doesn't really let us do anything new afaik, but dear lord does it trim things down a lot.

So! It turns out you can stick a bunch of different things into an :is() selector and apply the same rule to everything you put in there! I'm going to use the "no ships for X character" filter as an example here, so say you want to block every romantic pairing for Blorbo, Steve, and Glorp. You can do that like this:

.blurb:has(.relationships > a[href*="*s*"][href*="Blorbo"]),
.blurb:has(.relationships > a[href*="*s*"][href*="Steve"]),
.blurb:has(.relationships > a[href*="*s*"][href*="Glorp"]) {
  display: none !important;
}

Which works fine and isn't that awful to look at, but:

.blurb:has(.relationships > a[href*="*s*"]:is([href*="Blorbo"],[href*="Steve"],[href*="Glorp"])) {
  display: none !important;
}

also works! And doesn't involve typing .relationships > a[href*="*s*"] a million times sdkfjldkjskdkjl

And if for whatever reason you decide that you want to add the throuple Blorbo/Glorp/Steve as an exception to these rules, instead of doing that individually for each of your three filters you can just pop it on the end like so:

.blurb:has(.relationships > a[href*="*s*"]:is([href*="Blorbo"],[href*="Steve"],[href*="Glorp"]):not(a[href$="/tags/Blorbo%20Baggins*s*Glorp*s*Steve/works"])) {
  display: none !important;
}

So if you ever have a really complicated filter that you'd like to apply to two or more characters or tags, :is() is your friend!

Chapter 17: Making Filters Ignore Favorite Authors

Chapter Text

Okay, so the last chapter brought up the :is() selector, and the fact that it can wildly simplify obnoxiously complicated filters. I said it can't really let us do anything new, and while I stand by that being technically true, on a practical level there's stuff that's just. Not going to happen without it. Like, for instance, putting the same list of favorite authors into an exception clause for every tag filter! That would be hideously annoying, especially if you wanted to be able to add or remove authors from that list whenever you wanted.

But with :is(), if you want to construct your filters so that they ignore authors you already know you really like, you can do it like this:

.blurb:has(a:is([href*="Tag1"],
[href*="Tag2"],
[href*="Tag3"])):not(:has(a[rel="author"]:is([href*="/users/Author1/"],
[href*="/users/Author2/"],
[href*="/users/Author3/"]))) {
  display: none !important;
}

Where "Author1" is replaced by the author's username, and not their ID. If they're using a pseud, you'll want to grab the name in parentheses—so if you see AKA_CoolName (FavoriteAuthor) listed as the author of something, you would use just the "FavoriteAuthor" part. It will then let that author's works through the filters no matter which pseud they're using. You could also construct something similar using the user ID's and ".user-" classes, but I did it like this so that the whitelist is kind of human-readable lskdjfkslj

Chapter 18: Block all ships between two groups of characters

Chapter Text

So. Hypothetically, if you were in a fandom with, say, a bunch of young protagonists. And, y'know. A bunch of their parents. You might very reasonably want to draw a big bold line between those two clusters and tell a filter to hide every romantic pairing that crosses over it.

This is my filter like that! :D

Let's call these Group A and Group B, and the characters CharacterA1, Character B2, etc., just so it's easy to plug stuff in:

.blurb:has(.relationships > a:is([href*="*s*"],
[href*="%20x%20" i]):is([href*="CharacterA1"],
[href*="CharacterA2"],
[href*="CharacterA3"]):is([href*="CharacterB1"],
[href*="CharacterB2"],
[href*="CharacterB3"])) {
  display: none !important;
}

This hides any relationship tag with a slash or an " x " (so it should ignore platonic ones) that includes one character from Group A and one from Group B, while ignoring any relationships between members of the same group.

Chapter 19: Targeting just the first relationship tagged

Chapter Text

Alright, so! Filtering based off the first relationship tag. Can it be done? No, but also yes!

Right so we can't actually select the first relationship tag—this is because the warnings, relationships, characters, and freeforms are all kind of grouped together in a way that makes it really difficult to select the first one of a particular type. You can grab the first warning really easily, but it gets harder and harder the further down that list you go.

(This is actually not true anymore in many browsers! Not mine yet sadly, but you can check out the inspired works to see if a much more concise solution by Eli0t is an option for you!)

Fortunately, relationship tags come right after the archive warnings, and there can only be up to six of those. So even if we can't select for the first relationship tag, we can select for the "second tag on a fic with one archive warning", the "third tag on a fic with two warnings", and so on.

What this looks like, if you want a filter that blocks everything that doesn't have, say, "Blorbo Baggins/Steve" as the first relationship tag, is this:

.blurb:has(.warnings:nth-of-type(6)):not(:has(.relationships:nth-of-type(7):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))),
.blurb:has(.warnings:nth-of-type(5)):not(:has(.warnings:nth-of-type(6))):not(:has(.relationships:nth-of-type(6):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))),
.blurb:has(.warnings:nth-of-type(4)):not(:has(.warnings:nth-of-type(5))):not(:has(.relationships:nth-of-type(5):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))),
.blurb:has(.warnings:nth-of-type(3)):not(:has(.warnings:nth-of-type(4))):not(:has(.relationships:nth-of-type(4):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))),
.blurb:has(.warnings:nth-of-type(2)):not(:has(.warnings:nth-of-type(3))):not(:has(.relationships:nth-of-type(3):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))),
.blurb:has(.warnings:nth-of-type(1)):not(:has(.warnings:nth-of-type(2))):not(:has(.relationships:nth-of-type(2):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]))) {
  display: none !important;
}

And yeah, unfortunately you do have to change every tag. I tried to figure out how to format this so that there was only one Blorbo/Steve link, but with the way they're all nested together and have different numbers I haven't managed it.

Then, in reverse, we have this filter, which blocks every fic where Blorbo/Steve is tagged first (and thus presumably is the main ship):

.blurb:has(.warnings:nth-of-type(6)):has(.relationships:nth-of-type(7):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(5)):not(:has(.warnings:nth-of-type(6))):has(.relationships:nth-of-type(6):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(4)):not(:has(.warnings:nth-of-type(5))):has(.relationships:nth-of-type(5):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(3)):not(:has(.warnings:nth-of-type(4))):has(.relationships:nth-of-type(4):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(2)):not(:has(.warnings:nth-of-type(3))):has(.relationships:nth-of-type(3):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(1)):not(:has(.warnings:nth-of-type(2))):has(.relationships:nth-of-type(2):has(a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])) {
  display: none !important;
}

Edit: It seems these filters don't work correctly in Chrome, so here are some alternates that were tested on there instead!

For filtering out fics that don't have Blorbo/Steve as the first relationship tag:

.blurb:has(.warnings:nth-of-type(6)):not(:has(li:nth-of-type(7) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(5)):not(:has(.warnings:nth-of-type(6))):not(:has(li:nth-of-type(6) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(4)):not(:has(.warnings:nth-of-type(5))):not(:has(li:nth-of-type(5) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(3)):not(:has(.warnings:nth-of-type(4))):not(:has(li:nth-of-type(4) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(2)):not(:has(.warnings:nth-of-type(3))):not(:has(li:nth-of-type(3) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])),
.blurb:has(.warnings:nth-of-type(1)):not(:has(.warnings:nth-of-type(2))):not(:has(li:nth-of-type(2) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"])) {
  display: none !important;
}

And for filtering out fics that do have Blorbo/Steve as the first relationship tag:

.blurb:has(.warnings:nth-of-type(6)):has(li:nth-of-type(7) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]),
.blurb:has(.warnings:nth-of-type(5)):not(:has(.warnings:nth-of-type(6))):has(li:nth-of-type(6) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]),
.blurb:has(.warnings:nth-of-type(4)):not(:has(.warnings:nth-of-type(5))):has(li:nth-of-type(5) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]),
.blurb:has(.warnings:nth-of-type(3)):not(:has(.warnings:nth-of-type(4))):has(li:nth-of-type(4) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]),
.blurb:has(.warnings:nth-of-type(2)):not(:has(.warnings:nth-of-type(3))):has(li:nth-of-type(3) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]),
.blurb:has(.warnings:nth-of-type(1)):not(:has(.warnings:nth-of-type(2))):has(li:nth-of-type(2) > a[href$="/tags/Blorbo%20Baggins*s*Steve/works"]) {
  display: none !important;
}

Chapter 20: Hiding all but the first n tags of any type

Chapter Text

Alright! So this lovely change has recently rolled out to my browser, which lets you select the nth child of a specific class. This tutorial by Eli0t explains what it does, and how to use it to block fics that have too many tags of a certain type. So for instance if you wanted to hide anything with more than ten relationship tags, you could do that!

This is my little addition for hiding just the tags, so that a fic with 20 relationship tags would only display the first ten. Or five, or two, or whatever number you like! This works for character and freeform tags as well. Fandom tags are a little more complicated—long story short is that you can still kind of do this, but it's a bit jankier.

Okay, so, taking our "no more than ten relationship tags" as an example, we would want this:

.tags > li:nth-child(n + 11 of .relationships) {
  display: none !important;
}

The "li" element is the box that the tag links live in—we're going after this instead of the tag itself because this is where the commas go, and hiding the tags looks a lot nicer if those commas also go away. You will still get one stray comma at the end if you've hidden the last tag, but every fic blurb won't end with eight commas!, , , , , , , ,

The ".tags >" bit at the beginning just specifies that the "li" box should be the child of a "tags" class. I'm not sure this is 100% necessary, but "li" boxes are pretty common so it's nice to be a little extra specific to avoid accidentally hiding stuff we didn't mean to.

And then, there's the new form of "nth-child", which can now look for not just the nth child of a parent, but for the nth child of a parent with "relationships" as a class. This is what lets us specify the nth relationship tag instead of just the nth tag in general.

Lastly, the "n + 11" tells the nth-child selector that it's looking for anything that's the eleventh child or greater—so the twelfth and thirteenth and so on are all going to be grabbed by the same selector.

To modify this to suit your needs, you can replace ".relationships" with ".characters" and ".freeforms" (we'll get to fandom tags in a sec), and it should probably work with ".warnings" too for archive warnings, though I'm not totally sure how useful that would be when there can only be max six of them anyway. Then you want to swap out "11" for whichever number you want to start blocking, hence picking 11 to show only the first 10 tags.

Right, so, fandom tags. Say you want to show three fandoms and hide the rest. This kinda works:

.fandoms > .tag:nth-child(n + 4 of .tag) {
  display: none !important;
}

You will notice that this is pretty different from the filter we just used before. That's because fandom tags are stored differently. Extremely long overexplanation to follow (there are diagrams! ᗡ:) but as far as practical differences go: this is mostly the same, except that it will not hide any commas. They will be an extremely ugly eyesore on a fic with a lot of fandoms tagged and as far as I'm aware there is nothing to be done about that.

Why doesn't it hide commas? WELL I'M GLAD YOU ASKED! :D :D :D

(this is your last chance to escape before I start showing you diagrams)

OKAY. So for most of the tags, they are stored kind of like this:

Diagram of "li" boxes with links in them all nested in one big box. The commas are in the "li" boxes.

The important thing here: The commas are text. CSS cannot see the commas. CSS cannot hide the commas. We can only hide the boxes. If we hide the link boxes, the commas will stay, because they live in the "li" boxes. But if we hide the "li" boxes, we get rid of the commas.

Fandom tags are organized like this:

Diagram of how the fandom tags are organized. The commas are in the big box with all the links.

This time, there's no "li" box grouping the links and commas together. (Incidentally, this is why the "block fics by number of fandoms tagged" back in chapter 3 works, but doing the same thing for relationships or characters didn't. We were counting stuff in boxes, and in the first way of organizing things, each box only has one thing in it.) But! We can only hide the boxes! CSS can't see the commas because they aren't in a box. So we can hide the links, and leave a whole bunch of stray commas. Gross! But if we go up one step, and hide the box the commas are in, oops we hid the box containing all the fandom links :(

If anyone has a way around this I am DYING to know, but from what I can tell it's impossible to hide those commas :( :( :(

Chapter 21: Displaying only the first few tags of a certain type

Chapter Text

I recently got my hands on a new CSS selector! Specifically, this one:

:nth-child(n of .class)

Which finally lets us target tags of a specific "number", like the first relationship tag, or every character tag after the third. There's a lovely guide by Eli0t about how to use this in tag blocking over here, but for this I'm actually going to focus on tag hiding. (Mostly because this is the weird hyper-specific thing that I wound up doing with this code for my own site skin)

To start with, you might want to only display the first few relationship tags—if a fic has twenty tagged, you can hope they're ordered by relevance and you'll only be seeing the ones that are the most important to the story. Same thing with characters! For that, we can use code like this:

li:nth-child(n + 2 of .relationships) {
  display: none !important;
}

Note: I've been using "n" a lot to show where you should put in your own numbers, which is my bad—this type of selector actually has that n in it. To hopefully make it less confusing, I've bolded the two parts of this selector that act as "settings" to change.

In this case, 2 is the tag number where this filter will start hiding. So in this example, the filter will hide every relationship tag except the first one. Using "n + 1 of .relationships" will hide every relationship tag, while "n + 5 of .relationships" will leave the first four tags and hide all the rest. (Basically, add one to the max number of tags you want to see)

.relationships is the tag type, which is similar to what we've seen before. This can be used for .relationships, .characters, .freeforms, and .warnings for archive warnings. Beware of that last one though—the archive warnings are ordered alphabetically and some of the scary ones are near the end lol

One problem with this, though, is kinda the same as the problem with the archive warnings—what if there are tags that you want to be able to see, because they'll be important to deciding whether to read on or not? For example, you might have a ship that you like, but not in all circumstances or settings. You don't want to block it altogether, but you need to be able to see it when it's tagged. What do?

We can add a list of exceptions to the hiding filter like this:

li:nth-child(n + 2 of .relationships):not(:has(a[href$="/tags/Ship1/works"], a[href$="/tags/Ship2/works"], a[href$="/tags/Ship3/works"])) {
  display: none !important;
}

(I'm using relationship tags as an example, but this would work the same way for characters or freeforms.)

Or, you could instead hide only certain specific ships! For example, if there was a ship that you didn't care much about one way or the other, and its presence wouldn't impact whether or not you wanted to click through, you could hide it in general like this:

li:nth-child(n + 1 of .relationships):has(a[href$="/tags/Ship1/works"], a[href$="/tags/Ship2/works"], a[href$="/tags/Ship3/works"]) {
  display: none !important;
}

(This is not a terribly efficient way to do this, since we don't need to specify which child of the .relationships tag we are, but it should still do the trick!)

Then you could modify settings so that you'd still see it if it was the first relationship tag (and thus likely the main focus) like this:

li:nth-child(n + 2 of .relationships):has(a[href$="/tags/Ship1/works"], a[href$="/tags/Ship2/works"], a[href$="/tags/Ship3/works"]) {
  display: none !important;
}

Also, if you feel like getting really extracurricular about it, you could combine a general "hide all but the first x tags" filter with code like this:

.blurb:has(li:nth-child(2 of .relationships)) .relationships {
  background: goldenrod !important;
}

to highlight the "relationships" section (or characters, freeforms, etc.) on fics where some of those tags were hidden. That way you can tell which fics have more tags that you're not seeing. Just be sure to modify it to use the same number and type of tags as your hiding filters! You can change the color too—I do not recommend using goldenrod like I did while I was testing, because it is rather ugly, but you can pick whatever looks nicest with your site skin :)

Chapter 22: Weirdly enough, you can change other people's icons!

Chapter Text

Before you panic—not actually, this change only affects things on your end. To the rest of Ao3 absolutely nothing happens. But you can totally swap out other people's icons! I found this out mostly because I am very bad at remembering usernames and I kept getting people with the default icon confused with each other, so I wanted to see if I could stick other images in there as sort of 'placeholders' so that I could know at a glance who was who. And yeah! You totally can, even to the point of having your placeholder image get automatically overriden if they ever pick an icon.

Okay, so, a few things: I focused this on comments specifically, though you could probably also do something similar on people's profile pages. It affects both comments at the end of a fic, and those same comments in your inbox. However, it only works if the person is a registered user—they have links in their comments that let the CSS code tell them apart, and guests just don't.

Right! So the base code is this:

.comment:has(a[href*="/USERNAME/"]) > .icon img {
  content: url("https://www.your-image.jpg");
}

Which will override any user's icon. Again, for you and you only. And if you want to set it up so that it only affects that user if they are using the default icon (i.e. your image gets overwritten by theirs if they have one), then you can do that by just adding a link to the image like so:

.comment:has(a[href*="/USERNAME/"]) > .icon img[src="/images/skins/iconsets/default/icon_user.png"] {
  content: url("https://www.your-image.jpg");
}

Or you can change the default icon to be a picture of your choosing:

.comment > .icon img[src="/images/skins/iconsets/default/icon_user.png"] {
  content: url("https://www.your-image.jpg");
}

Or you could do this, and turn Ao3 into your own personal Mishapocalypse! (though you will first need a picture of him because the link I put here is made up):

.comment > .icon img {
  content: url("https://www.misha-collins.jpg");
}

Chapter 23: Hide "crossovers" between synonymous fandoms

Chapter Text

This one's probably going to be more useful to some fandoms than others, but: say you're in the fandom of a book that has a TV series, or an anime that has a manga, and you want to look for crossovers. You go over to that part of the filters, and you hit "Show Only Crossovers", and suddenly you're greeted with a wall of fics that are a crossover between "The Fandom (Book)" and "The Fandom (TV)" which probably isn't what you were looking for. (I believe some fandoms like Marvel have a metatag that solves this problem, but not all of them.)

Turns out this is way more solveable with site skins than you might think! The previous filter for getting rid of mega-crossovers can be modified a bit to work in reverse, and grab fics with less than three fandoms tagged instead. Like so:

.blurb:not(:has(h5.fandoms > .tag:nth-of-type(3))) {

  display: none !important;

}

Then you stick on a couple extra :has() selectors to make sure it's only doing that with your specific not-actually-a-crossover fandoms:

.blurb:has(.tag[href$="/tags/The%20Fandom%20(TV)/works"]):has(.tag[href$="/tags/The%20Fandom%20(Book)/works"]):not(:has(h5.fandoms > .tag:nth-of-type(3))) {

  display: none !important;

}

and voila!

...Except that now whenever you aren't looking at crossovers you've probably hidden half your fandom. Which is not ideal, and neither is having to constantly swap between site skins. (Trust me on that one.)

But! The webpage actually looks different when you're searching for crossovers, because now the button marked "Show Only Crossovers" has a big black dot showing that you pushed it! So there must be something in the html that distinguishes between a normal fandom search, a crossover exclusion, and a crossovers-only search.

That button, in the code, looks something like this:

label input[id="work_search_crossover_t"]

And when it's been clicked, and only when it's been clicked, it also has a "checked" property, so it can be targeted like this:

label input[id="work_search_crossover_t"][checked="checked"]

All of the fic blurbs are stored somewhere inside a big giant class that holds the whole search page, aka ".works-index". And with our checked-off button, we can use CSS to target only a crossovers-only works index, like this:

.works-index:has(label input[id="work_search_crossover_t"][checked="checked"])

And then we can modify our filter from earlier to only apply to fics that are inside such a crossovers-only works index, like this:

.works-index:has(label input[id="work_search_crossover_t"][checked="checked"]) .blurb:has(.tag[href$="/tags/The%20Fandom%20(TV)/works"]):has(.tag[href$="/tags/The%20Fandom%20(Book)/works"]):not(:has(h5.fandoms > .tag:nth-of-type(3))) {

  display: none !important;

}

And at least so far when I've tested it, it seems to only activate and start hiding fics when you're in a crossovers-only search! So it should be possible to browse the archive normally while still using this site skin, and only have it kick in when you actually want it to.

Chapter 24: Toggling filters on and off

Chapter Text

Have you ever wanted to apply a site skin filter, but only when you're searching in one specific tag? Do you dream of being able to turn an absurdly complicated filter on and off without the hassle of switching to a completely different skin? I sure am hoping I'm not the only one with these problems, because boy have I overengineered some solutions!


Okay, so, first one: filters that only apply when you're looking in a specific tag. This should work for any canonical tag, be it a fandom, a character, a relationship, or a freeform. Normally we might write a tag filter something like this:

.blurb:has(a[href$="/tags/BlockTag/works"]) {
  display: none !important;
}

which will apply everywhere. These blurbs are sort of like boxes, in which all the tags and summaries and junk go. And the blurb boxes are all in one giant box containing the whole search page. In the CSS code that giant box goes by "works-index". The works-index box will also, if you happen to be looking at the results for a certain tag, have a link to that tag at the top! That link looks something like this, if you want to try highlighting it:

h2.heading > .tag[href$="/tags/SearchTag"] {
  background: yellow !important;
}

Note: be careful not to add /works onto the end of the url here! On fics, a tag will redirect to its main search page (archiveofourown.org/tags/SearchTag/works), but the link in the header goes instead to a sort of info page, where you can see tag synonyms and stuff like that (archiveofourown.org/tags/SearchTag).

Now, we combine all that together to get this:

.works-index:has(h2.heading > .tag[href$="/tags/SearchTag"]) .blurb:has(a[href$="/tags/BlockTag/works"]) {
  display: none !important;
}

This targets any fic blurb that is inside a works-index box whose header is our "SearchTag", which applies the filter only on that search page. I've been using this personally for minor or semi-minor characters, who are often tagged in a lot of fics that don't actually focus on them. For example, a filter like this pairs really well with "nth character tag" type filters, like so:

.works-index:has(h2.heading > .tag[href$="/tags/Blorbo%20Baggins"]) .blurb:not(:has(li:is(:nth-child(1 of .characters),
:nth-child(2 of .characters)) a[href$="/tags/Blorbo%20Baggins/works"])) {
  display: none !important;
}

This will hide any fic without "Blorbo Baggins" within its first two character tags, as long as we're searching in Blorbo's tag.


So, that's a type of filter that toggles on or off depending on what tag you're searching in. But what if you want to create a sort of "toggle" that you can turn on or off in any search, which adds or removes a specific filter? Turns out that's possible too, though fair warning that it's a touch janky lol

The basic principal here is the same. We want to do something like this:

.works-index:has(thing I can toggle on and off) .blurb:has(a[href$="Tag"]) {
  display: none !important;
}

but for a toggle that won't actually do anything to the filtering. Now, there's multiple ways to approach this, but the one I went with involves typing something into the "Search Within Results" field. Because it turns out putting something like this in the search bar (quotes included! we'll talk about why at the end):

"pickle farm"

will look like this in a css filter:

input[id="work_search_query"][value*="pickle farm"]

(Using *= instead of $= is important, because the quotation marks in our search query will end up in the value. So technically the value is ""pickle farm"", but like most coding languages CSS does not like when you put quotes inside of your quotes. Hence the *= so that we don't have to worry about that part.)

Now, we can put basically whatever we want into the css code just by typing in the search bar. Which lets us then tell our filter to look for these toggle searches, and either turn on if we've typed "pickle farm" into the search bar:

.works-index:has(input[id="work_search_query"][value*="pickle farm"]) .blurb:has(a[href$="/tags/Tag/works"]) {
  display: none !important;
}

Or be on by default, and turn off if we type "pickle farm" into the search bar:

.works-index:not(:has(input[id="work_search_query"][value*="pickle farm"])) .blurb:has(a[href$="/tags/Tag/works"]) {
  display: none !important;
}

However. If you've tried this, you've probably noticed that in 99.9% of tags and fandoms, searching for "pickle farm" will come back with... zero results. Which makes this pretty useless as it is. But! If you instead search for -"pickle farm", which instead excludes fics containing "pickle farm", then voila! You've excluded (probably) zero works, and the [value] property we're looking for is now "-"pickle farm" instead, which will still be picked up by our filter.

Choosing what to use as a toggle mostly comes down to something that you'll remember offhand, but which is also very unlikely to show up organically in a tag or summary. For example, a toggle like this:

-"myfilters turn on blorbo filter"

is pretty vanishingly unlikely to interfere with your search at all. And if you want to check if a toggle will cause a problem, you can always search for it like this in AO3's advanced search like so:

"myfilters turn on blorbo filter"

and see if it gets any hits! As long as searching for your toggle without the minus sign gets you zero results, than searching with the minus sign (so excluding your toggle) should give you the exact same results as not putting your toggle in the search field at all.

This is why the quotes are important—["pickle farm"] will only find fics with the exact phrase "pickle farm" somewhere in the tags, summary, notes, etc. But [pickle farm], not in quotes, will find fics with both "pickle" and "farm" but not necessarily together, i.e. a summary about how Blorbo A and Blorbo B are starting a farm together and Blorbo B is craving pickles. Basically, the quotes make it a lot less likely to accidentally catch fics with our toggle search.

Chapter 25: Tag hiding update (no more stray commas! (mostly))

Chapter Text

Someone recently reminded me that I never actually posted a fix to the stray commas problem, when it came to hiding specific tags rather than hiding an entire fic. (For a quick recap: if there's a tag that you don't mind reading, but don't want to know about in advance, either for spoiler reasons or because it just isn't super important to you, you can! But the method I used back in chapter two leaves a stray comma for every hidden tag and it's a horrible eyesore.)

So! A few options/reasons for hiding. I'm going to start with the simplest, which is if a tag isn't really going to inform you one way or another on whether you want to read a fic. As an example, I'm just literally going to use one of my filters, which is the "No Archive Warnings Apply" tag. When this tag is by itself, you can kinda tell that it's a no warnings apply by the fact that there aren't any other warnings, and when it's tagged with like three other archive warnings (as it sometimes is), then it doesn't really mean that much anyway lol. So I personally decided to hide it to focus my attention on the other warnings. Here's the code for it:

.warnings:has(.tag[href*="/No%20Archive%20Warnings%20Apply/"]) {

  display: none;

}

I've bolded ".warnings", because the code for this will actually be different depending on the type of tag. The long explanation for why I'm doing this is in chapter 20, but the short version is because those are the boxes that the commas are in and I hate stray commas. Stealing a diagram from that chapter:

Diagram of "li" boxes with links in them all nested in one big box. The commas are in the "li" boxes.

If we hide the links, that leaves the stray commas. So we want to hide the "li" boxes instead, but if we just put something like this:

li:has(.tag[href*="/No%20Archive%20Warnings%20Apply/"])

then we'd run into the minor problem that lots and lots of boxes are "li" boxes, including the whole entire blurb, and we don't want to hide the whole entire blurb in this case. Hence using the tag type classes instead. These are as follows:

.warnings for archive warnings

.relationships for relationship tags

.characters for character tags

.freeforms for freeform tags

.fandoms for fandom tags

Though be warned that doing this with fandom tags will still leave a stray comma. If you want to know why, the explanation for that is in chapter 20. With diagrams :))))

So for example, if you want to hide "Horror" or "Happy Ending" so that those elements can be a surprise for you, then you would use ".freeforms" in the filter with those tags, like so:

.freeforms:has(.tag[href*="horror" i],

.tag[href*="happy%20ending" i]) {

  display: none;

}

(I also highly recommend using the " i" to mark filters like this which look for a phrase within the tags as case-insensitive, which means that "[href*="horror" i] can pick up both "Horror", and "Some minor horror elements". Just remember to leave the " i" inside the brackets but outside the quotes!)

If you're looking to hide stuff more generally, like chatty tags of any sort that have a specific phrase in them, then you can do something like this to cover multiple types:

li:is(.relationships,

.characters,

.freeforms):has(.tag[href*="Hide%20Me" i]) {

  display: none;

}

Lastly, if there's a character or relationship that you're very neutral about—like, you don't dislike it, but you don't care about it that much either—then you might want to hide that tag in certain circumstances. It won't influence your decision to try a fic at all, if it's like the fourth ship listed. But what if it's the main ship? Now you might not want to read that fic unless it's got a very cool premise, if it's going to be focused on something you're not that into. I had exactly this problem, so I came up with this filter:

li:nth-child(n + 2 of .relationships):has(a[href$="/tags/Sir%20Meh*s*Mehbur%20Mehsington/works"]) {

  display: none;

}

It can be used for a character by just swapping out ".characters" for ".relationships". I also set it up so that it would hide the tag as long as it wasn't the first ship tagged, but that can be adjusted by changing "n + 2" to be "n + 3" to hide it as long as it's the 3rd relationship tag or later, "n + 4" to hide it if it's the 4th relationship tag or later, and so on.

Anyways, I hope this is helpful! It took me...

Then I promptly realized that this filter that literally just worked ten minutes ago is no longer working. I go to inspect element on my webpage, because what the actual hell, and oh look! Now it works! :D

I turn off inspect element and refresh the page. The filter ceases to work.

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaa

...a while to figure it out, and to be honest I mostly forgot about it until I happened to fix it up for use in my own filters, and then just never thought to post it here lol

(The incoherent screaming is an excerpt from the chapter draft of me trying to do this like a year ago)