Closed nounder closed 10 years ago
When raising issues here on GitHub, please take a few minutes to read the contributing guidelines. They provide tips on the kind of information to put into an issue. Raising issues with just one or two lines leaves a lot of work for the people reading this to go and find out what you're talking about.
In this case the {{body_class}}
outputs page
for static pages, so why are you expecting that it output page-template
? Why do you think it should output different things depending on what .hbs
file is used, rather than when the properties of the model are different?
It would be great if you could update your issue with some more details.
Thank you, @ErisDS and sorry for any inconvenient. I've never contributed to open-source project.
*-template
class should depends on .hbs
files because that would provide more information to theme developer about what's going on. Also, it would be easier to style HTML elements when .hbs
file has different structure.
I really like this idea, it offers a lot of flexibility and future-proofing in a way that makes sense.
However, this impacts on the larger "how-to-organise body classes" discussion, which merits some consideration:
<body class="post-template">
<body class="page-template">
Single specific class for pages.
.post-template .post-title,
.page-template .post-title {
//styles
}
<body class="post-template">
<body class="post-template page-template">
All .post-template styles apply by default, but can be overridden with .page-template styles.
.page-template h1
override .post-template h1
? or Does it end up needing to be .post-template.page-template h1
? (ew)<body class="single post-template">
<body class="single page-template">
An abstracted class for singular view (post and pages) + a specific class
There's also some crossover on the rest of the page.hbs
template that bothers me. We use {{#post}}
and {{post_class}}
and so on. This is another area where we use the "post" naming convention do stuff with a page. So making specific rules for page templates in body_class while ignoring the rest, feels weird.
I guess each approach treats the concept of a "page" in a different way:
The first definitely isn't true. The second is true, but results in an ugly implementation.
I don't think there's any perfect answer to this one. We're currently doing option 2 (cascading), which I like less and less. I'm vaguely leaning towards option 3 (object oriented), but not completely sure.
I think we can pretty much rule out the first, specific type of classes for all the reasons you state,
Next, viewed in the context of https://github.com/TryGhost/Ghost/issues/1969, does it make more sense to have:
post-template page-template page-template-contact
or
single page-template page-template-contact
To me the latter more clearly makes sense at this stage. Each item clearly refers to a level in a hierarchy of specificity, whereas in the first case, two classes are seemingly at the same 'level'.
I don't think the single
abstracted class is overkill. Having 2 types of single view is 100% more than what we had before. Even given that we will only ever have 2, I don't think we should treat pages like a second class citizen, which is kinda what the Cascading-style body classes looks like.
I definitely don't like option one. Semantically, it simply isn't true. Option two lends itself to confusion, specifically in the aforementioned inheritance/override issues.
Option three, however, seems to be the most feasible to me. It cleanly solves the inheritance/override issues presented by option two. Personally, I use LESS to create my stylesheets, so writing an abstracted class isn't a lot more work, and it's well-organized. Even without LESS, assigning template-specific code to classes isn't a chore. The .single
class would contain the bulk of the common view code.
Touching on @ErisDS's comment about #1969, I think the use of the abstracted .single
class in her second example is the best approach to solving the inheritance confusion.
Option three is also the most scalable, in my opinion. Setting the foundation for future growth makes sense, and this seems like a minimal and reasonable investment toward that goal.
Just been talking to Kezz about this, who gave me an interesting idea. She said that as a theme developer she rarely uses generated body classes because she prefers to write her own wherever possible and have maximum control. Also, dynamically generated body classes can fast turn source code into tag-soup when everything under the sun ends up inside them.
So what if we rewind a couple of steps here.
What is the point of body classes at all? - To allow themes to style different page templates in specific ways based on the body tag (the most high-level parent element which can reach everything else on the page as a descendant). The template file (post.hbs for example) can't get to the body tag, so it needs to be generated.
There are some things which a theme cannot account for, which must be dynamically generated because they are based on content or a setting in Ghost admin. Eg. "featured" - a theme cannot set that manually, it must be toggled on and off by the post author inside Ghost admin. So we use {{post_class}}
to conditionally insert a featured class when it's appropriate and when not.
We should be asking, though, do we need to dynamically generate all of our classes? Or could we simply create controls for theme authors to do it themselves on an as-needed basis?
Eg. first 2 lines of page.hbs could be
{{!< default}}
{{body_class add="page-template"}}
NB: This is dummy syntax for the sake of articulating an idea
Hopefully that's self-explanatory, but it would allow the theme to set what the body tag should be for this particular use-case. It could also accept a parameter of "remove" to remove a dynamically generated class if applicable.
It would also allow theme authors to choose for themselves between options 1, 2 and 3 listed above. Which I feel is quite a powerful idea.
_NB2: this concept doesn't work everywhere. Eg. "home" and "archive" both use index.hbs - they need a dynamically generated bodyclass, no two ways about it. But where it's possible to hand control over to the theme author, perhaps we should.
If I understand correctly, you are suggesting that there should be some sort of syntax that can be placed inside a page or post template that will change what classes are output by body_class inside the default layout.
Whilst an interesting idea that makes sense from the theme developer's perspective, I'm not sure how this could be achieved. The concept of a layout file is provided by the express-hbs
library, which is what allows us to use handlebars syntax with express.
It allows you to define a {{{body}}}
placeholder inside the layout. Then when the page template is rendered, it finds the layout, treats it as though that is actually the template and sets the original page template content as the data for a key called body
such that it will be output where {{{body}}}
is defined.
There is another feature of express-hbs called content blocks, which allow you to define a block in the layout, and then define the content for that block in the page template.
I guess that we could implement our own version of this, but both the output and modifying helpers could not be called {{body_class}}
.
I think this is pretty advanced and complex functionality to achieve a simple thing. I'm not sure if we're not getting lost down a rabbit hole, purely because it's not yet possible for people to filter the output of {{body_class}}
- is it worth waiting until we have that feature available to see how theme developers get on with it?
I think blocks would be a simple solution to this, without adding too much complexity.
We could modify the template files as so:
default.hbs
<body class="{{body_class}} {{{block "bodyClass"}}}">
page.hbs
{{!< default}}
{{#contentFor 'bodyClass'}}this-is-my-custom-class here-is-another {{/contentFor}}
Reducing {{body_class}}
to only contain the bare minimum of default styles that are needed and allowing for custom extension should allow for an increase in flexibility with theme creation.
One nit that I do have is that express-hbs
doesn't allow for default block content like django's templates does. That would have allowed for a little bit more flexible usage.
For me, as @sethlilly said, option 3 seems make sense. I personally use SASS for everything, so duplicate css rule would not be much of a bother. In fact, I can just separate the style differences and call it a truce. As for the custom classes, I will simply use the outermost wrapper on each template to fiddle with.
I think this is pretty advanced and complex functionality to achieve a simple thing. I'm not sure if we're not getting lost down a rabbit hole, purely because it's not yet possible for people to filter the output of {{body_class}} - is it worth waiting until we have that feature available to see how theme developers get on with it?
No, because filtering body_class won't ever be possible purely with a theme. It would require an accompanying app. We're talking about pure-theme functionality / defaults.
However, if what @hswolff is saying is possible anyway with handlebars, without us needing to add anything to core, then I don't see much point in adding it to core.
We can just set body_class with sensible default (option 3, above?) and leave it up to the theme author if they want to use body_class or replace it entirely with their own custom thing, or use both.
So I think the conclusion to all of this is to simply make "single" appear in body_class for both posts and pages, and "post-template" and "page-template" appear in body_class respectively.
Hi all, @JohnONolan asked me to jump in on this, so here's my 2 cents.
I'd say, keep it simple. If the view is a singular view (page or post), add a singular
class. From there, you already have page
and post
, so why not just keep those? If the *.hbs
file is not page
or post
, add a new CSS class to denote the file name, without the .hbs
part (for example, another-post-type
). Adding -template
at the end makes the CSS class unnecessarily long, for it's purpose.
If the file in question is always displaying a type of content, the -template
is also redundant, as we know it's a template. :)
In terms of adding custom CSS classes, it may become quite complex, having to check a bunch of logic on each page load and add the CSS classes as a parameter on {{body_class}}
. That being said, a parameter for classes which should be added on each load would be a nice to have.
Perhaps a config variable in the theme would be a good start, for adding custom CSS classes. If not, there's always a JavaScript-driven solution, instead, which produces the same result (albeit in a less elegant manner).
I hope this helps. :)
I think the problem with dropping '-template' from the body classes, is that the body classes are then the same as the post classes?
That’s also true, yes.
Matt Cohen
WordPress & Web Developer
On Monday 27 January 2014 at 1:43 PM, Hannah Wolfe wrote:
I think the problem with dropping '-template' from the body classes, is that the body classes are then the same as the post classes?
— Reply to this email directly or view it on GitHub (https://github.com/TryGhost/Ghost/issues/1967#issuecomment-33360782).
I think that the main result of this conversation is that object oriented style is best, however we haven't really reached a clear definition of what should happen.
Here's what does happen, assuming every single post/page has a tag of 'hello':
Home page i.e. the route is /
: home-template
Paginated page i.e. /page/2/
: archive-template
Normal post: post-template tag-hello
Static page post: post-template page tag-hello
The suggestion made by the original post here, was that the -template
classes should be used to determine specifically which template is currently being used.
So if a static page post was using the post.hbs
it would get post-template
but if it was using page.hbs
it would be given page-template
.
Furthermore, I believe it is anticipated that page
should be dropped from static page posts.
This would leave us with the following:
Home page (uses index.hbs): home-template
Paginated page (also uses index.hbs): archive-template
Normal post (uses post.hbs): single post-template tag-hello
Static page post (using post.hbs): single post-template tag-hello
Static page post (using page.hbs): single page-template tag-hello
This doesn't make a great deal of sense to me personally... Firstly, in one case template refers to the template/view file used, and in another it doesn't and secondly I have no way to know whether the overall page I'm styling contains a single post or a single page. If we add page
back in we end up with:
Home page (uses index.hbs): home-template
Paginated page (also uses index.hbs): archive-template
Normal post (uses post.hbs): single post-template tag-hello
Static page post (using post.hbs): single page post-template tag-hello
Static page post (using page.hbs): single page page-template tag-hello
But then the page class is the same as the one output by the post_class which does:
Normal post: post tag-hello
Static page post : post tag-hello page
Featured post: post tag-hello featured
Featured static page (doesn't make sense but oh well): post tag-hello page featured
I believe what makes the most sense is to use:
Home page (uses index.hbs): home index-template
Paginated page (also uses index.hbs): home paged index-template
Normal post (uses post.hbs): single post-template tag-hello
Static page post (using post.hbs): single static post-template tag-hello
Static page post (using page.hbs): single static page-template tag-hello
Tag page (uses index.hbs): tag index-template
Tag page (uses tag.hbs): tag tag-template
Tag Paginated page (uses index.hbs): tag paged index-template
Tag Paginated page (uses tag.hbs): tag paged tag-template
If we can settle on a solution, then I think we would need to do it in two stages. 1) add all the new classes, release the next version of Ghost, 2) remove all the old no longer wanted classes. Otherwise blog layouts are going to break :(
update: one additional idea is to use -view
or another word instead of -template
to indicate what .hbs file is being used to render the content. That could be added without confusion, and leftovers cleaned up later.
I'm not sure I agree with Kezz. If the default body classes provided are good I tend to use them. In drupal you get the following classes and I tend to use them when needed.
front/not-front logged-in/not-logged-in node-type-{page/post} page-node-{id}
Having a not-front
is actually useful at times, when you want to target everything but the front-page, i.e. both pages and posts. When it comes to the suggested classes above I'm not sure I see the need of -template, why not just have index
, tag
, and so on? It will make the css cleaner and smaller in my opinion. While -template does make it a bit clearer I doubt anyone will get confused over that?
One last thing, having users create their own body classes will make it a bit more messy. Different users will have different preferences. This might not be a bad thing but having everyone use the same will make it easier/faster to look at other users themes and understand them. If I were to pick my body class names I might use something like inloggad/inte-inloggad, start-sida/inte-start-sida and very few people would understand that directly.
@ErisDS I think your last comment is on the right track - and you also had an identical approach to what I had in mind RE simply adding a class like paged
.
I'm beginning to realise, however, that the premise set out at the start of this issue is somewhat flawed, which is the concept that the bodyclass is representing the template being used to render the page. The use-case for the body class is actually to describe the content on the page, and style it accordingly.
Eg.
I may use post.hbs for both posts and pages, but the point of the bodyclass is to allow me to style them differently. I could hide comments on pages, and leave them visible on posts. The point is that the bodyclass differentiates between the two regardless of the theme file being used to render the page.
Conversely, if they both received the bodyclass of post-template - there would be no benefit in having a bodyclass at all. The only way to change the styling would be to add another template file. Which isn't desirable.
I think we (inc. me) have gone waaaaayy too far down the abstraction/OOCSS rabbit hole, so I'm coming back out for some fresh air and suggesting that we largely stick with what we have - per the 'specific' option outlined above.
Index - [this is the default, it needs no class]
Home - home-template (should only ever appear on /
)
Page 2 - paged
Tag archive - tag-template, tag-[name]
Tag archive page 2 - tag-template, tag-[name], paged
Post - post-template, tag-[name]
Page - page-template, tag-[name]
And an exception to the rule, where the theme file absolutely dictates the bodyclass:
Custom page - page-template, page-[slug], tag-[name]
I think content vs. template focus is a really good point, especially in the context that the {{content}}
blocks Hannah recently described for us do give the option of setting body classes on a per template basis if we choose.
Technically, though not best practice perhaps, a theme developer could even create an alternative default.hbs file and load it for a specific template if they needed to style elements that couldn't be dealt with inside said template. (I tested that out and it worked but I don't know if that might cause issues).
If there's a set of classes we want to use often, I'm still tending towards thinking as theme devs we have the option to add them to a reusable starter theme if we choose. That also allows us to namespace theme classes so they can't be overridden by plugins later.
On the other hand a plugin developer that doesn't have the ability to reach in and change template files might want to include content specific styling. For example, a video related plugin might ask users to apply the tag "video" and then use that to hook in their particular presentation.
But technically for theme devs, even that could be handled with {{content}}
blocks too on an as needed basis, with only the tags a theme will include styles for injected into the body class.
So considering these factors I'm wondering, perhaps the area to consider most might be what plugin devs will need, given theme devs have methods in place to add any classes we want to target, but plugin developers will rely on whatever core gives them to work with?
That is with the exception of being able to identify secondary archive pages so themes can do things like shrinking large cover images when not on the home page.
This issue ties in with several other issues:
{{is}}
helperWhat became apparent from several discussions, was the need to have a global concept of 'context' that describes where you are in a Ghost blog at any given moment. That context can then be used to inform how to apply core body classes, how the {{is}}
helper, and context in filters should work, and even how to know what data you have at your finger tips at any given time.
We came up with a system of contexts, which is defined in a rather large table here: https://github.com/TryGhost/Ghost/wiki/Context-aware-Filters-and-Helpers#context-table
This table lays out what body classes are currently output, and what should be output given the new system.
In order to move towards this new context, we need to add the new classes in all of the given contexts. We will then give theme developers 2 releases to update their themes. Then the old classes which are no longer present in the new system will be removed.
The work required in this issue is therefore:
/page/*
add the class paged
page-{{slug}}
for pages with custom templatesThe old classes will be removed in #2597
When page.hbs template is used,
body_class
list "post-template" instead of "page-template". "*-template" class name should change based on currently used.hbs
filename. That would be really helpful when developing themes.