Re: Tabbed Interfaces in CSS

On Wed, Apr 22, 2009 at 1:30 PM, Brad Kemper <brad.kemper@gmail.com> wrote:
> On Apr 22, 2009, at 7:51 AM, "Tab Atkins Jr." <jackalmage@gmail.com> wrote:
>> That seems to depend a *lot* on very undefined behavior for the
>> appearance property, which *shouldn't* have anything to do with
>> behavior at all.  As Giovanni says, appearance is just a shorthand way
>> of saying "set all these properties so that the element looks like X
>> widget in the UA".
>
> The main part of the proposal was about allowing a :checked state on other
> elements, to allow such things as tab behavior. Setting the appearance to
> look like a tab was not a requirement to get this behavior, just as a quick
> way for setting the visual style (and for making the example brief). As I
> mentioned, I'd hoped it might also take care of the alignment of one tab
> with another, but this was not a critical part of the proposal.

Oh, indeed, I recognize that :checked is the major part, and it's a
good way to solve the problem.  But there's several good ways, and the
devil is in the details surrounding the problem.  ^_^  Pulling tabs
from the card content seems to have become a requirement, and the
details of displaying tabs are very important as well.  If they won't
display well, and there's no way to *make* them display well in a
proposal, then it's a non-starter.  (I am not implying that this is
the case for your proposal, mind.)

>> You're relying on appearance to group tabs,
>
> No, I wasn't. I proposed a new property called 'radio-group', that would
> accept an identifier. Any other element with the same identifier would be
> part of the same group.

Sorry, I didn't mean group them behavior-wise.  Appearance is being
used in your example to group them visually.  I don't think that's a
good idea.

>> move them around the page,
>
> I only said the it would be helpful if appearance could take care of the
> horizontal positioning to prevent improper overlap with a previous tab of
> the same group (some OS might prefer a certain amount of overlap or margin
> for it's tabs). But the propsal does not require it, and I mentioned a
> couple other ways to deal with that horizontal positioning of the tabs that
> could be used if appearance was not, or if appearance could not be made to
> work that way.

It seems to me that the display of tabs is pretty critical to authors,
so we need to make sure there are good options here.  Any tabbed
display proposal needs to be paired with a way to, you know, *display
the tabs* in a way that will be acceptable to authors.

>> and defeat a display:none applied to their parent.
>
> I suggested no such thing.

Apologies; I see what you were doing now.  Appearance:none removes
*all* default formatting from fieldset, but doesn't *hide* it.  Then
you pull the legend out, and display:none all other children, leaving
an empty fieldset with no other appearance properties set, which makes
it effectively invisible.

This works.  ^_^

>>  In addition to all
>> this behavior, it presumably applies a UA-default style to the tabs,
>> and possibly cards, making it difficult/impossible to restyle them as
>> desired.
>
> No, applying the UA-default style would be the primary reason to use
> appearance. It would not be required. I could have given a sample with
> padding, border, margin, background, etc. But thought it would not be as
> clear and consise for an example for what I was trying to illustrate with
> the example. What I was trying to show was how a checked state could work
> for creating a tabbed interface, not to show all the ways a tab could be
> visually styled. Appearance could take care of the visual style (and
> theoretically the left positioning) in a much more concise way, provided you
> could use it to provide the diffent looks of a tab (front/selected,
> back/non-selected, top, side, bottom, etc.).

Displaying a front/back tab in a UA-default way seems like an
appropriate job for appearance, but you are using it as well to
somehow move the tabs to the top/bottom/side/etc.  This is requiring
appearance to handle positioning as well, which is bad.  If you are
*relying* on the appearance-magic to handle tab positioning properly,
then how does an author handle it when they don't want the UA-default
style?  This really needs to be defined (or at least be possible to
define) in a way without any recourse to magic.

If you could provide a simple ugly example just using border, padding,
and margin, while still achieving the desired tab *layout*, I'd be
happier.  ^_^

>> It seems like Template Layout could solve this much more easily and
>> extensibly, actually.
>
> More easily than what? I did mention template layout as a method for
> handling the right and left positioning of the tabs.

Well, it solves the problem that tabs may come from various places but
have to gather in a single location.

Frex, look at the fieldset/legend example.  Let's say the first
fieldset is :checked currently.  In this case, then, the order of
content is:

fieldset-one content before the legend
fieldset-one legend
fieldset-one content after the legend
fieldset-two legend

That's... not really what you want.  It's basically an accordion,
because the card contents will be distributed between the tabs.  I
think you may have overlooked this, and thus not really understood why
Giovanni and I keep harping on the degree of appearance magic you're
depending on.  You *need* the ability to flow tabs out of their normal
position to make this work properly as a tabbed layout; luckily
Template Layout gives us a decent way to do this.  ^_^

>> form { display: "a" "b"; }
>> fieldset:not(:checked) { display:none; position:b; radio-group:my-tabs; }
>> fieldset legend { position:a; /* insert generic tab styling here */ }
>> fieldset:checked legend { /* style the active tab */ }
>> fieldset:not(:checked) legend { /* style the inactive tabs */ }
>
> So you are basically agreeing with my main points. The styling you left out
> could be provided by appearance or my setting borders, etc. yourself, which
> is what I always said. The main changes I proposed (:checked elents other
> than inputs, and radio-group to group the selection behavior) are there. It
> seems like you are trying to argue with me, but your argument shows general
> agreement.

Yes, I am (basically agreeing with you).  Sorry if that's not obvious.  ^_^

>> The only potential problem is the display:none.  It hides the element
>> and *all* children.
>
> That's why I didn't do it that way. Just give it no height and width and no
> other styling that would be visible.

Yup, got that now.

>>  I presume that Template Layout doesn't interact
>> with normal inheritance, so it would still cause problems.
>
> I would not assume any changes in inhertance rules.

Good, neither would I.

>> You use
>> appearance:none to address this issue in some unspecified way, but
>> perhaps there's another way to say "hide the element and static-flow
>> children"?
>
> I am only using that to hide the appearance of the fieldset. I used the
> universal selector to hide it's children (as I explained), and then a legend
> selector with the same specificity to show that one part. You could just as
> well use the 'not' pseudo-class to hide all but the legend. A fieldset with
> no border, padding, or visible style, and no visible children except the
> legend gets me just what I was looking for.

Understood now.

>> That seems useful to me in general - it would allow abspos
>> elements who live outside of the parent anyway to possible stay
>> visible.
>
> Perhaps, but not required for this.

Understood now.

>>>>> Yours requires a link behaviors spec to prevent unwanted
>>>>> scrolling (or that people find it acceptable for clicking on a tab
>>>>> would
>>>>> scroll the page).
>>>>
>>>> Maybe.  It's also possible that it just includes magic which would fix
>>>> the issue.  This magic also has the benefit of eventually being
>>>> translatable into proper rules if Link Behaviors gets properly adopted
>>>> (and has this ability) - a simple ":tab{target:no-change;}" (or
>>>> whatever) added to the UA default stylesheet would do it.
>>>
>>> Fair enough. I was trying to minimize magic-reliance in mine, but for the
>>> best effect I have a little for appearance to do, or a reliance on
>>> floating-to-a-named-spot-type-of-thing, or else a somewhat less ideal
>>> presentation (see last part of my tabs example explanation).
>>
>> Floating to a named spot is more-or-less covered by template layout
>> now, and can be done as I outlined above.
>
> Fine. There are more than one way to skin a cat, and what I am proposing
> does not insist on one way or another for the positioning of the tabs
> themselves, although some ways would be handier than others, or have other
> advantages.

Nod.  We just need to make sure that there's at least *one* way to do
it well.  Your proposal, by itself, didn't seem to offer that.

>>  I find it much preferable
>> to hacking appearance into doing this.
>
> I do not consider it a hack that tab appearances can set some sort of
> 'min-left' on itself internally to get the proper OS tab alignment with
> other tabs in it's group. But I do not require that; it would just be an
> appreciated nicety.

As expressed above, it's not the "min-left" or whatever that's the
problem.  It's the fact that you have to flow the tabs out of their
normal position into a new location, at least if you are extracting
them from the card contents.  If you don't, you get accordion display
instead.

>>>>> Mine has neither of these requirements, but just extends
>>>>> an existing pseudo-class to more elements, and adds a couple properties
>>>>> to
>>>>> indicate radio groups and for defaults.
>>>>
>>>> But without some magic generation of tabs from card content, it has
>>>> bad fallback behavior.
>>>
>>> Nope. Good fallback behavior is its best quality. It only prefers a
>>> little
>>> magic for lining up the tabs, or using one of the other proposals for
>>> moving
>>> things around. It might even be able to use template layout for that. So
>>> magic is not an absolute requirement.
>>
>> Yes, once you've added the ability to extract tabs from the cards
>> (solving the issue of hiding the card without hiding the extracted tab
>> in the process), then fallback is just fine.
>
> I did solve that in every example I provided, even the earliest version.

Oh, yes, certainly.  Sorry, I'm reiterating that as much for my own
benefit as anyone else's.  I want to make sure that we all agree on
the same requirements, and that it is clear to outside observers just
what those requirements driving our proposals are.  I've tried to
follow conversations that don't do that - it gets difficult when
you're not in the same design mindset as the original authors.  ^_^

>>  It still has bad
>> fallback when you're doing a more complex tabbed layout with the tabs
>> defined outside of the cards, though (which is why I based my proposal
>> on links, which are still good in this case).
>
> Only insomuch as if someone wants to put a defacto label far from the
> element it is labeling, I do notprevrnt you from doing so. If you want to
> put the label inide an anchor or vice versa, you can do that too.

Ah, yeah, that'd work.  Just use <a> *and* <label> together, the
latter providing :checked interaction and the former providing good
fallback behavior.  This would still require some sort of Link
Behavior stuff to avoid scrolling, but at this point that's a minority
concern (rather than being part of the core proposal, like it is in
mine).


Please understand that at this point I'm very happy with the
possibilities of your proposal.  It seems to accomplish the necessary
behavior in a simple way, it interacts with the existing event model
in HTML well (just update :checked whenever a click event bubbles
through) which should make it more attractive to implementors and easy
to understand for authors, the default use provides good fallback
naturally and it allows decent fallback in the next most common use,
and another proposal currently in the pipeline and looking promising
(Template Layout) provides us all the tools to style this well.  To
top it all off, it even interacts well with javascript: you can change
the active card in js by shooting a click event at the element, or
*prevent* a card from raising by eating click events on its tab before
they can bubble through to the card.

All in all, this *feels* like a winner to me.

~TJ

Received on Wednesday, 22 April 2009 21:16:48 UTC