I’ve tried using img:first-of-type to select the first image of a note, but it still selects every image on the page.
What I’m trying to do
I’m trying to make a css snippet that will make the first image in a note a sort of “banner image” that floats to the top of the page and spans the whole width of the note. Preferably with the first header spanning over it. Essentially, I’m trying to copy this:
Ah ok, too bad he didn’t post the css back then. You could also try the Obsidian Discord Channel, I think there is a lobby named #csssnippets or something. Lots of CSS gurus there
img:first-of-type alone will not work, since the images are not direct siblings but each in their own tree of nested divs. Actually, this is good news, since this makes it possible to have a banner for multiple open tabs.
Since just one level higher up the parent divs of imgs are siblings, I thought that something like .cm-content div:has(img):first-of-type img should do the trick. Unfortunately, it does not. I still post it, so maybe somebody can take it up and make it work…
So far I’ve managed to create a banner image that adapts to the note width using @gapmiss’ advice. To use it, you type obsidian-banner in the frontmatter. This is the code:
i made few tweaks from your previous example. i must say, make it work in Live Preview is a bit tricky because using position: absolute will throw off editing experience of your note. Luckily I remember a trick I used with display: contents. Anyway, here’s what I managed…
use image alt “banner” i.e. ![[imagefile.jpg|banner]] as a way to target a specific image for banner. can use first image by targeting the first one after yaml, but i feel this image alt gives better flexibility
make the image banner in live preview not affecting editing experience. position: absolute will make the first few top lines almost impossible to select
added option to adjust vertical positioning (albeit just 3 options in total – center (default), higher (20% higher using image alt “higher”), and lower (20% lower, image alt “lower”
make the note title slightly overlap the banner. need to use position: relative and z-index: 1 to make the title on top of the banner.
I tried to explore gradient filter that makes bottom of the picture gradually whiter (or any other color) but to no success
the full css snippet with a number of tweaks
/* banner using css only -- https://forum.obsidian.md/t/css-how-to-style-the-first-image-in-a-note/52839/ */
/* make the div (in LP) containing the image doesn't control the css box-sizing */
.internal-embed.image-embed[alt*="banner"] { display: contents; }
/* original forum post snippet with minor tweak */
.obsidian-banner img[alt*="banner"] {
position: absolute;
top: 0;
left: 0;
height: 200px;
width: 100%;
margin-right: auto;
margin-left: auto;
object-fit: cover;
object-position: 50% 50%;
overflow: hidden;
user-select: none;
}
/* add option to adjust vertical position by adding the alt metadata "higher" or "lower" */
.obsidian-banner img[alt*="banner"][alt*="lower"] { object-position: 50% 30%; }
.obsidian-banner img[alt*="banner"][alt*="higher"] { object-position: 50% 70%; }
/* original forum post with minor tweak to make it overlap */
.obsidian-banner .inline-title {
position: relative;
padding-top: 150px;
z-index: 1;
}
/* minor tweak for me, since i have snippet to make image has rounded corner */
.obsidian-banner.is-readable-line-width img { border-radius: revert; }
/* minor tweak for me, to hide snw block reference counter for the banner */
.internal-embed.media-embed.image-embed.is-loaded + .snw-reference.snw-embed {display: none;}
superb! this will go into my boilerplate/reference notes. my knowledge on gradient so far has been limited to background-color. this definitely will come handy in the future.
anyway, i tried with targeting the first image. but i couldn’t make it work for editing view/live preview. it works just fine for reading view. either there’s another hidden first image or codemirror just behave differently (coz when i choose the last image, it selected the second last in my note).
so the best bet right now is using the image alt there. with that u can place the image practically anywhere in the note and it won’t disrupt any flow i can think of right now. plus u might want the custom control to adjust the position (my example using [[|higher]] to make a notch higher.
Perhaps the CSS has() pseudo-class could be used to target the img without using the alt tag. With Obsidian’s recent upgrade to Electron v21, has() is now available. I may experiment with it but am curious if someone else(more adept) might take a crack at it.
There is some trickery to be done, which could potentially target the first image (without doing the alternate text trick, which is a far better solution). For the reading view it looks something like this:
Now the first image will have a background-color of yellow, whilst the other have a blue background. In other words, if you want to set something for the first image, you need to revert that setting for all other images.
Of course, in the live preview, the CSS is different, and a lot more messy, so it’s not as easy to find selectors which can be considered siblings which make that trick useful in the reading view. You could target all images using something like .cm-contentContainer :has(div.cm-line > dv.image-embed, div.image-embed) div.image-embed, but this selector doesn’t co-operate with the sibling selector, ~, since the selector targets elements on different levels.
Another option, could be to use the :nth-child(n of <selector>) selector, but this is not supported in chromium until version 111, and we’re currently at ver 106 for Obsidian.