-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EthicalAds: Default to fixedfooter for smaller screens #447
base: main
Are you sure you want to change the base?
Conversation
This is something I've wanted for a little while. I don't think we're quite ready to ship it, but I think it makes sense in a lot of cases. I'm generally becoming more excited about this placement, especially when the floating one is pretty intrusive.
b9e342e
to
a4ef3ab
Compare
433c4ef
to
0f36172
Compare
Marking this ready for review after our previous conversation. I'd like to see us doing the fixed footer by default more, since I think it's a much more user friendly ad format. We're hopefully gonna work on a nice fixed footer/header format with a small image, which I think will be even better, but I think this is a nicer UX for default. In general I really dislike how not integrated the ad feels on non-Sphinx themes, so I think this is a "gentler" approach to ads that isn't quite as impactful for users who want to move to RTD for non-Sphinx themes. NOTE: This is somewhere that it would be interesting to have a feature flag, so that we could test it a bit before rolling it out more widely. |
Looks like this hides the "sidebar" toggle on docify: https://test-builds.readthedocs.io/en/docsify/#/ -- and there wasn't an element I could find to add margin-bottom to, because I think they're fixed positioning.... The struggle of placement on arbitrary content :( |
Yeah, I think we should keep adding more frameworks to our heuristic detection and create better ad placement for specific documentation tools. Sphinx is well integrated because we did the work there. The same happens with all the other we have listed at: Lines 73 to 142 in 8ccaa33
We can do the same for Markdoc, mdbook and similars to have better integrations on those as well. It shouldn't be hard. We need to find the right CSS selector. I'm not opposed to have a better default for frameworks we don't know; but we for those we are aware they exist and people are using them, we should integrate them better by using custom positioning.
As I mentioned in the meeting, I would not use feature flags for this, but use a |
Show how simple is to add a better ad positioning for a documentation tool that we know. 1. Find the CSS selector that allows to detect the framework 2. Find the CSS selector for the ad position 3. Add small CSS for styling if required Related #447
I added an example of what I'm saying in #470. You can see it's pretty easy to create these custom positioning based on the framework. I think they will always work better (less intrusive, nicer look&feel) than a generic default. You can try to follow those steps and add a better positioning for Markdoc, for example. |
By they way, when performing visual changes, I would really appreciate having a screenshot of how it looks --that way is a lot easier to do a review; since it doesn't require me to clone the PR and testing it locally. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@humitos point on per-tool styling is probably better overall, but just noting a couple things with the approach here.
src/ethicalads.js
Outdated
// TODO: THIS IS A HACK. IS THERE A BETTER WAY? | ||
// Add margin to the bottom to avoid hiding bottom of content | ||
const root_node = document.querySelector(docTool.getRootSelector()); | ||
root_node.style.marginBottom = "2em"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting a couple issues here, I haven't tried playing around with the styling here.
Altering style rules through Element.style
ends up just adding a style="..."
attribute to the element, which has a couple issues:
- Inline
style
attributes can be blocked by CSP rules as unsafe. - Inline
style
attributes have the highest specificity in CSS, so the user loses control of this styling.
In both cases, it's better to use classes to apply rules to these elements.
src/ethicalads.js
Outdated
@@ -158,6 +158,20 @@ export class EthicalAdsAddon extends AddonBase { | |||
placement, | |||
elementInsertBefore.lastChild, | |||
); | |||
} else if (window.innerWidth <= 1300 && window.innerWidth > 768) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed this logic and the same above. These conditionals are only evaluated once, so don't catch the window resizing or rotating. Users have to reload before the placement style would shift in this case. These widths might be better off as CSS media queries, which are reactive.
Show how simple is to add a better ad positioning for a documentation tool that we know. 1. Find the CSS selector that allows to detect the framework 2. Find the CSS selector for the ad position 3. Add small CSS for styling if required ![Screenshot_2024-12-12_12-12-47](https://github.com/user-attachments/assets/7b3dac1f-701f-4e55-83b4-13bb86e96690) Related #447
Next steps:
|
I think this PR should be ready to be merged. I'm adding a class to the main content node to add a bottom margin so hopefully the ad doesn't cover the content. The other option I was wondering about is adding a close button to the ad, just in case the content under it needs to be accessed. @davidfischer thoughts on building that into the placement itself, or should we customize it? |
@ericholscher can you post screenshots of how it looks under different doc tools? That would help with the review. |
Screenshots attached to description. |
font-size: 20px; | ||
line-height: 20px; | ||
.ethical-fixedfooter-margin { | ||
margin-bottom: 5em; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@agjohnson Is there a way to have this match the height of the ad instead of a random height?
Seems like you could hack it with something like:
// Get the height of the target element
const targetElement = document.querySelector('.target-class');
const matchingElement = document.querySelector('.matching-class');
// Match the height dynamically
matchingElement.style.height = `${targetElement.offsetHeight}px`;
but I don't think there's a way to do it non-dynamically, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even calculating the margin at load time, it will break when resizing the window.
I think the problem here is position: fixed
(that comes from EthicalAd client CSS). Using a more selector with more specificity (😉 @agjohnson ) we can override it. Example showing how it works:
#readthedocs-ea {
position: static;
}
With this, we don't need to add the extra class .ethical-fixedfooter-margin
to all the elements as you are doing in https://github.com/readthedocs/addons/pull/447/files#diff-10e47ee23788d0e8d3d4e13cee726fd04c8fe035922a74ac1c7d432db1dfb9faR191
I understand this works because we are adding this element as the last one in the document.body
.
However, it does not work well in all the documentation tools because the ad may end behind a scroll 😞
Demo
Material for MkDocs
Sphinx Furo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't pure CSS solution here given the fixed footer is a separate element from the elements you're adding classes to for the margin -- there isn't a way to reference between elements like this unless one element is a direct descendant. In this case you have more options and calc()
might be able to get there.
I'd avoid a JS solution here especially using Element.style
-- my note above applies here.
It feels like we should have multiple explicit styles by viewport size, not necessarily try to do this dynamically -- that is we'd have explicit heights for mobile, table, desktop widths.
// Add margin to content and footers to avoid hiding content | ||
const root_node = document.querySelector(docTool.getRootSelector()); | ||
const footers = document.querySelectorAll("footer, .footer"); | ||
|
||
if (root_node) { | ||
root_node.classList.add("ethical-fixedfooter-margin"); | ||
} | ||
|
||
footers.forEach((footer) => { | ||
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need to be a lot more precise adding margins into user content like this. Adding margin into the main document content is probably not what we want either, as there isn't a direct link between the main document content and the bottom of the frame.
I suppose I'm not convinced we should be adding margins into nested elements yet. document.body
is probably the place we should be adding padding (body { padding-bottom: 1rem; }
) for a fixed footer, but not where we should insert an ad placement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just not try and just the bottom margins at all? The issue is that it covers up fixed position content on other themes (eg. mkdocs-material), so I wasn't sure what the right approach was.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I had to choose, I would prefer to cover footer content than breaking layout (adding weird margins). In either case, we can work on "better placement for that particular doctool" when we see it or when users complain 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I was trying to build a better placement for mkdocs-material specifically, because I know that's one we want to support, so understanding the "right" way to bump the ad above the footer is still useful. I agree maybe we just add that to the theme-specific support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have a specific positioning for Material for MkDocs that's working already: https://docs.pypi.org/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but not for smaller screen sizes, like we are discussing?
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); | ||
|
||
// Inject the actual ad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my comment above was about not adding the fixed footer to document.body, but this feels like we should be adding the fixed footer placement to document.body. Do we want it full width of the frame or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want it full width of the frame or not?
I think it should be full width, yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't be showing on the RTD theme, since that has a custom placement. I'm not really sure what the change being suggested here is -- isn't the ad getting injected into the document.body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ad is being injected on RTD theme here. I think that happens because of the current logic: "if the specific placement it not above the fold, we show the default placement". The "default placement" now is fixedfooter, and that's why it's being shown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the idea is good, but it's hard to do it correctly in a reliable way. I don't think it has to be perfect 1, but at least I would like to fix those cases where it seems to be broken (not using the full width of the page and adding a lot of blank space at the bottom).
With those changes, I think I will feel more comfortable deploying this and keeping an eye on those new cases where it breaks to fix them as we go.
This change will affect all the documentation pages which looks like a big change to deploy something we don't feel comfortable about. We talked about adding AddonsConfig.ethicalads_type = "text"
and add it a few projects to start. That may be still an option as well.
Footnotes
-
making it reactive could be a v2 of this implementation, for example ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted some options here, but I'd overall agree that the fixed footer is going to be the hardest placement to get correct across all tools/themes. Text ad would indeed be an easier place to start for a site wide default placement.
This seems like it might be close but it does need some more precision. Altering users styles without precision is bound to cause some friction or confusion with users.
// Add margin to content and footers to avoid hiding content | ||
const root_node = document.querySelector(docTool.getRootSelector()); | ||
const footers = document.querySelectorAll("footer, .footer"); | ||
|
||
if (root_node) { | ||
root_node.classList.add("ethical-fixedfooter-margin"); | ||
} | ||
|
||
footers.forEach((footer) => { | ||
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need to be a lot more precise adding margins into user content like this. Adding margin into the main document content is probably not what we want either, as there isn't a direct link between the main document content and the bottom of the frame.
I suppose I'm not convinced we should be adding margins into nested elements yet. document.body
is probably the place we should be adding padding (body { padding-bottom: 1rem; }
) for a fixed footer, but not where we should insert an ad placement.
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); | ||
|
||
// Inject the actual ad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my comment above was about not adding the fixed footer to document.body, but this feels like we should be adding the fixed footer placement to document.body. Do we want it full width of the frame or not?
font-size: 20px; | ||
line-height: 20px; | ||
.ethical-fixedfooter-margin { | ||
margin-bottom: 5em; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't pure CSS solution here given the fixed footer is a separate element from the elements you're adding classes to for the margin -- there isn't a way to reference between elements like this unless one element is a direct descendant. In this case you have more options and calc()
might be able to get there.
I'd avoid a JS solution here especially using Element.style
-- my note above applies here.
It feels like we should have multiple explicit styles by viewport size, not necessarily try to do this dynamically -- that is we'd have explicit heights for mobile, table, desktop widths.
// placement, | ||
// elementInsertBefore.lastChild, | ||
// ); | ||
} else if (window.innerWidth > 768) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a case for matchMedia
: https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
Noted earlier that this check isn't dynamic currently, it's only evaluated once. Using matchMedia
as an event gives a way to do this after page load.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't easily reconfigure the ad without doing another API call, so we don't want it to be dynamic. We want to have a single ad load on page load, and stick with that, otherwise it will get weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really sure what is being suggested here, but feel free to update this PR with an approach that y'all think will work.
// placement, | ||
// elementInsertBefore.lastChild, | ||
// ); | ||
} else if (window.innerWidth > 768) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't easily reconfigure the ad without doing another API call, so we don't want it to be dynamic. We want to have a single ad load on page load, and stick with that, otherwise it will get weird.
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); | ||
|
||
// Inject the actual ad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't be showing on the RTD theme, since that has a custom placement. I'm not really sure what the change being suggested here is -- isn't the ad getting injected into the document.body?
// Add margin to content and footers to avoid hiding content | ||
const root_node = document.querySelector(docTool.getRootSelector()); | ||
const footers = document.querySelectorAll("footer, .footer"); | ||
|
||
if (root_node) { | ||
root_node.classList.add("ethical-fixedfooter-margin"); | ||
} | ||
|
||
footers.forEach((footer) => { | ||
footer.classList.add("ethical-fixedfooter-margin"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just not try and just the bottom margins at all? The issue is that it covers up fixed position content on other themes (eg. mkdocs-material), so I wasn't sure what the right approach was.
This is something I've wanted for a little while.
I don't think we're quite ready to ship it,
but I think it makes sense in a lot of cases.
I'm generally becoming more excited about this placement,
especially when the floating one is pretty intrusive.
Demo