css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <div class="text">
	
	<h1>Attempting to build a CSS Grid Schedule</h1>
	
	<p class="meta">By <a href="https://mrwweb.com">Mark Root-Wiley</a> | <a href="#description">See below for details</a></p>
	
	<hr>
	
</div>

<div class="schedule">
	
	<span class="track-slot" aria-hidden="true" style="grid-column: track-1; grid-row: tracks;">Track 1</span>
	<span class="track-slot" aria-hidden="true" style="grid-column: track-2; grid-row: tracks;">Track 2</span>
	<span class="track-slot" aria-hidden="true" style="grid-column: track-3; grid-row: tracks;">Track 3</span>
	<span class="track-slot" aria-hidden="true" style="grid-column: track-4; grid-row: tracks;">Track 4</span>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-0800;">8:00am</h2>

	<div class="session session-1 track-1" style="grid-column: track-1; grid-row: time-0800 / time-0900;">
		<h3 class="title">Talk Title</h3>
		<span class="time">8:00 - 9:00</span>
		<span class="track">Track: 1</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<div class="session session-2 track-2" style="grid-column: track-2-start; grid-row: time-0800 / time-0900;">
		<h3 class="title">Talk Title</h3>
		<span class="time">8:00 - 9:00</span>
		<span class="track">Track: 2</span>
		<span class="author">Mike Rofone</span>
	</div>	
	
	<div class="session session-3 track-3" style="grid-column: track-3-start; grid-row: time-0800 / time-0830;">
		<h3 class="title">Talk Title</h3>
		<span class="time">8:00 - 8:30</span>
		<span class="track">Track: 3</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<div class="session session-4 track-4" style="grid-column: track-4-start; grid-row: time-0800 / time-1000;">
		<h3 class="title">Talk Title</h3>
		<span class="time">8:00 - 10:00</span>
		<span class="track">Track: 2</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-0830;">8:30am</h2>
	
	<div class="session session-5 track-3" style="grid-column: track-3-start; grid-row: time-0830 / time-1000;">
		<h3 class="title">Talk Title</h3>
		<span class="time">8:30 - 10:00</span>
		<span class="track">Track: 1</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-0900;">9:00am</h2>
	
	<div class="session session-6 track-1" style="grid-column: track-1-start /track-2-end; grid-row: time-0900 / time-1000;">
		<h3 class="title">Talk Title</h3>
		<span class="time">9:00 - 10:00</span>
		<span class="track">Track: 1</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-1000;">10:00am</h2>
	
	<div class="session session-7 track-many" style="grid-column: track-1-start / track-4-end; grid-row: time-1000 / time-1030;">
		<h3 class="title">Take a break!</h3>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-1030;">10:30am</h2>
	
	<div class="session session-8 track-1" style="grid-column: track-1-start; grid-row: time-1030 / time-1130;">
		<h3 class="title">Talk Title</h3>
		<span class="time">10:30 - 11:30</span>
		<span class="track">Track: 1</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<div class="session session-9 track-2" style="grid-column: track-2-start; grid-row: time-1030 / time-1230;">
		<h3 class="title">Talk Title</h3>
		<span class="time">10:30 - 12:30</span>
		<span class="track">Track: 2</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<div class="session session-10 track-4" style="grid-column: track-4-start; grid-row: time-1030 / time-1100;">
		<h3 class="title">Talk Title</h3>
		<span class="time">10:30 - 11:0</span>
		<span class="track">Track: 4</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-1100;">11:00am</h2>
	
	<div class="session session-11 track-3" style="grid-column: track-3-start; grid-row: time-1100 / time-1130;">
		<h3 class="title">Talk Title</h3>
		<span class="time">11:00 - 11:30</span>
		<span class="track">Track: 3</span>
		<span class="author">Mike Rofone</span>
	</div>
	
	<h2 class="time-slot" style="grid-column: times; grid-row: time-1130;">11:30am</h2>
	
	<div class="session track-1 track-many" style="grid-column: track-1-start; grid-row: time-1130 / time-1230;">
		<h3 class="title">Lunch!</h3>
	</div>
	
		<div class="session track-3 track-4 track-many" style="grid-column: track-3-start / track-4-end; grid-row: time-1130 / time-1230;">
		<h3 class="title">Lunch!</h3>
	</div>
	
</div>

<div class="text" id="description">
	<hr>
	<h2>Background &amp; Inspiration</h2>
	<p>This project is inspired by the WordCamp.org schedule building tool and its shortcomings. <a href="https://meta.trac.wordpress.org/ticket/3117">Meta trac ticket #3117</a> is tracking improvements to the schedule builder and layout.</p>
	<p>With the intention of implementing this via a CMS, I'm attempting to create a schedule layout capable of automatic generation from session metadata ("track," start time, and end time). This is primarily achieved through the use of named grid-lines for tracks and time slots. Inspiration is due to <a href="https://css-tricks.com/making-a-bar-chart-with-css-grid/">"Making a Bar Chart with CSS Grid."</a></p>
	<p>Edge-cases currently supported:</p>
	<ul>
		<li>Sessions spanning any length of time. (For ease of reading, this demo only supports 30-minute increments, but this could easily be adapted for the 5-minute increments allowed by WordCamp.org sites.)</li>
		<li>Gaps between sessions during sessions without similar gaps</li>
		<li>Sessions spanning multiple contiguous tracks</li>
	</ul>
	<p>Edge-cases <em>not</em> supported:</p>
	<ul>
		<li>Sessions spanning multiple, <em>non-contiguous</em> tracks (though future improvements to CSS Grid may allow this)</li>
		<li>Overlapping session times within the same track</li>
	</ul>
	
	<h2>Fallbacks & Accessibility</h2>
	
	<p>Note that the source order is based on <em>start time</em> and not as it may appear when simply reading left-to-right in the grid (see the Session #s which align with source order). This is presumably a good thing as it means that the non-grid fallback (similar to the current schedule mobile view) and output read to screen readers is chronological. Each time in the left column is a Heading 2 with session titles being Heading 3s, producing the following document outline:</p>
	<ul>
		<li>1: Page Title
			<ul>
				<li>2: Time
					<ul><li>3: {Sessions}</li></ul>
				</li>
				<li>2: Time
					<ul><li>3: {Sessions}</li></ul>
				</li>
				<li>2: Time
					<ul><li>3: {Sessions}</li></ul>
				</li>
			</ul>
		</li>
	</ul>
	
	<h2>Other Notes</h2>
	<ul>
		<li>By using the <code>fr</code> unit for <code>grid-template-rows</code>, each session's height visually aligns with its length. A more compact but less clear view can be achieved with the <code>auto</code> keyword instead of <code>fr</code>.</li>
		<li>Due to the nature of the <code>fr</code> unit and the variable number of tracks, the CSS grid template rules will need to be generated dynamically so they only span the time between the first and last session. This shouldn't be too hard, but it's worth noting here.</li>
		<li>The source order of the session details is important but can be safely rearranged within the "card" via grid or flexbox for lots of creative layouts. Presumably the session time (in the session blocks) and track could be visually [accessibly] hidden if desired by the themer.</li>
	</ul>
	<h2>In-progress list of implementation requirements:</h2>
	<ul>
		<li>The major admin-side change required for this schedule is that <strong>it requires site editors to specify either an end time or length of the session</strong>. For the purposes of display, an end time is slightly more valuable, though could just as easily be generated from a session length which is probably easier for users to enter.
			<ul>
				<li>The layout CSS code for each session requires a modified version of the start and end times: <code>time-hhmm</code> specified in 24hr time.</li>
				<li><ins>Following some discussion on Slack, the current plan is to use a new required Length field with a sensible default. Changing the value will update the default value for future sessions.</ins></li>
			</ul>
		</li>
		<li>The grid CSS will need to be uniquely generated for each session schedule. That likely means outputting an inline style block using a prefixed class associated with that schedule (in case multiple schedules appear on the same page, a common occurrence, e.g. Saturday & Sunday schedules). Each grid template outputs named lines in the format <code>time-hhmm</code> for 5 minute increments starting at the first session and ending at the last session. (This demo only uses 30 minute increments as a proof-of-concept.) Each line is separated either with <code>1fr</code> or <code>auto</code> as the length between.</li>
		<li>Tracks similarly use named lines though with an extra name so that each track has both a defined start and end line.</li>
		<li>As mentioned above, the session source order is:
			<ul>
				<li>Heading 2 containing start time</li>
				<li>All sessions with that start time. Session title = Heading 3.</li>
				<li>Heading 2 with next start time</li>
				<li><em>etc&hellip;</em></li>
			</ul></li>
		<li>For styling, each session should be given a unique class and a class for what track it's in, possibly with an additional class for any session in multiple tracks.</li>
	</ul>
</div>
            
          
!
            
              /*************************
 * LAYOUT
 *************************/
body {
	padding: 50px;
	counter-reset: session;
	max-width: 1100px;
	margin: 0 auto;
	line-height: 1.5;
}

.track-slot {
	display: none;
}
.session {
	margin-bottom:  1em;
}

@supports( display:grid ) {
	@media screen and (min-width:700px) {
		.schedule {
			display: grid;
		}
		
		/* a background for the sticky tracks */
		.schedule::after {
			display: block;
			content: '';
			position: sticky;
			top: 0;
			grid-column: track-1 / -1;
			grid-row: tracks;
			z-index: 999;
			background-color: rgba(255,255,255,.9);
		}
		
		.track-slot {
			display: block;
			padding: 10px 5px 5px;
			position: sticky;
			top: 0; /* otherwise seeing a gap above in at least Firefox. */
			z-index: 1000;
		}
		.session {
			margin: 0;
		}
	}
}

.schedule {
	grid-gap: 1em;
	grid-template-rows:
		[tracks] auto
		[time-0800] 1fr
		[time-0830] 1fr
		[time-0900] 1fr
		[time-0930] 1fr
		[time-1000] 1fr
		[time-1030] 1fr
		[time-1100] 1fr
		[time-1130] 1fr
		[time-1200] 1fr
	 /* Note 1:
		In this format, gridlines will need to be "named" in 24hr time
	
		Note 2: Use "auto" instead of "1fr" for a more compact schedule where height of a slot is not proportional to the session length. Implementing a "compact" shortcode attribute might make sense for this!
	*/
	;
	grid-template-columns:
		[times] 4em
		[track-1-start] 1fr
		[track-1-end track-2-start] 1fr
		[track-2-end track-3-start] 1fr
		[track-3-end track-4-start] 1fr
		[track-4-end]
	;
}

/*************************
 * VISUAL STYLES
 *************************/
.text {
	max-width: 750px;
	font-size: 18px;
	margin: 0 auto 50px;
}

.meta {
	color: #555;
	font-style: italic;
}
.meta a {
	color: #555;
}

hr {
	margin: 40px 0;
}

.session {
	padding: .5em;
	border-radius: 2px;
	font-size: 14px;
}

.title,
.time-slot {
	margin: 0;
	font-size: 1em;
}

body {
	counter-reset: session-count;
}
.title::before {
	counter-increment: session-count;
	content: 'Session #' counter(session-count) ': ';
}

.track-slot,
.time-slot {
	font-weight: bold;
	font-size:.75em;
}

span {
	display: block;
}

.track-1 {
	background-color: #1259B2;
	color: #fff;
}

.track-2 {
	background-color: #687f00;
	color: #fff;
}

.track-3 {
	background-color: #544D69;
	color: #fff;
}

.track-4 {
	background-color: #c35500;
	color: #fff;
}

.track-many {
	display: flex;
	justify-content: center;
	align-items: center;
	background: #ccc;
	color: #000;
}

ins {
	text-decoration: none;
	background-color: #ddffdd;
}
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console