إنشاء خط زمني افقي - الإصدار الثاني
📊 تحسين تجربة المستخدم (UX)
- تقديم المعلومات بطريقة زمنية مرتبة ومنطقية
- تسهيل فهم التسلسل الزمني للأحداث
- جعل المحتوى أكثر جاذبية وتنظيمًا
⚙️ فوائد تقنية
- أداء عالي: لا يحتاج إلى مكتبات خارجية أو JavaScript معقد
- سرعة التحميل: تأثيرات CSS أخف من الصور أو الفيديوهات
- سهولة الصيانة: تعديل المحتوى دون الحاجة لتغيير الهيكل الأساسي
🎨 فوائد تصميمية
- مرونة في التصميم: يمكن تخصيص الشكل والألوان بسهولة
- تأثيرات بصرية جذابة: حركات وتغيرات عند التحويم أو التمرير
- تنسيق متسق: مظهر موحد لجميع العناصر
📱 فوائد للتوافقية
- تجاوب كامل: يعمل على جميع أحجام الشاشات
- توافق مع المتصفحات: يدعمه جميع المتصفحات الحديثة
- إمكانية الوصول: يمكن تحسينه لذوي الاحتياجات الخاصة
💻 فوائد للتطوير
- سهولة التنفيذ: لا يحتاج لمهارات برمجة متقدمة
- إعادة الاستخدام: يمكن استخدام النموذج لمشاريع متعددة
- تحديثات سهلة: إضافة أو حذف عناصر دون التأثير على التصميم
الجداول الزمنية باستخدام CSS توفر حلًا مثاليًا لعرض المعلومات الزمنية بطريقة جذابة وسهلة الفهم مع الحفاظ على أداء الموقع وسرعته.
شرح متكامل لشفرة الجدول الزمني العمودي
الهيكل الأساسي (HTML)
قسم المقدمة
<section class="section intro">
<div class="container">
<h1>Horizontal Timeline v2 →</h1>
<p>Timeline v1 <a href="#">here</a></p>
</div>
</section>
- تصميم أنيق مع سهم اتجاهي في العنوان
- رابط للإصدار السابق للمقارنة
القسم الرئيسي للجدول الزمني
<section class="timeline">
<div class="info">
<img src="face.svg" alt="">
<h2>Company History</h2>
<p>وصف قصير...</p>
<a href="">Learn more →</a>
</div>
<ol>
<li>
<div>
<time>1934</time> محتوى الحدث...
</div>
</li>
</ol>
</section>
التصميم والتنسيقات (CSS)
نظام الألوان
لوحة ألوان متكاملة باستخدام متغيرات CSS
تخطيط متجاوب
يتحول إلى عرض عمودي على الشاشات الصغيرة
تأثيرات بصرية
تدرجات لونية وشريط تمرير مخصص
.timeline {
display: grid;
grid-template-columns: 320px auto;
gap: 20px;
}
.timeline ol li {
display: inline-block;
width: 160px;
height: 5px;
background: var(--white);
}
.timeline ol li:not(:last-child)::after {
content: "";
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--midnight-green);
}
(JavaScript)
function setEqualHeights(el) {
let maxHeight = 0;
el.forEach(item => {
if(item.offsetHeight > maxHeight) {
maxHeight = item.offsetHeight;
}
});
el.forEach(item => {
item.style.height = `${maxHeight}px`;
});
}
window.addEventListener("load", init);
الكود كاملا
<section class="section intro">
<div class="container">
<h1>Horizontal Timeline v2 →</h1>
<p>Timeline v1 <a href="https://codepen.io/sami20a/full/gbOdMww" target="_blank">here</a></p>
</div>
</section>
<section class="timeline">
<div class="info">
<img width="50" height="50" src="https://assets.codepen.io/210284/face.svg" alt="" />
<h2>Company History</h2>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium</p>
<p>
<a href="">Learn more ></a>
</p>
</div>
<ol>
<li>
<div>
<time>1934</time> At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium At vero eos et accusamus et iusto odio dignissimos.
</div>
</li>
<li>
<div>
<time>1937</time> Proin quam velit, efficitur vel neque vitae, rhoncus commodo mi. Suspendisse finibus mauris et bibendum molestie. Aenean ex augue, varius et pulvinar in, pretium non nisi.
</div>
</li>
<li>
<div>
<time>1940</time> Proin iaculis, nibh eget efficitur varius, libero tellus porta dolor, at pulvinar tortor ex eget ligula. Integer eu dapibus arcu, sit amet sollicitudin eros.
</div>
</li>
<li>
<div>
<time>1943</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1946</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1956</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1957</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1967</time> Aenean condimentum odio a bibendum rhoncus. Ut mauris felis, volutpat eget porta faucibus, euismod quis ante.
</div>
</li>
<li>
<div>
<time>1977</time> Vestibulum porttitor lorem sed pharetra dignissim. Nulla maximus, dui a tristique iaculis, quam dolor convallis enim, non dignissim ligula ipsum a turpis.
</div>
</li>
<li>
<div>
<time>1985</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>2000</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>2005</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li></li>
</ol>
</section>
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap");
:root {
--white: #fff;
--black: #323135;
--crystal: #a8dadd;
--columbia-blue: #cee9e4;
--midnight-green: #01565b;
--yellow: #e5f33d;
--timeline-gradient: rgba(206, 233, 228, 1) 0%, rgba(206, 233, 228, 1) 50%,
rgba(206, 233, 228, 0) 100%;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
button {
background: transparent;
border: none;
cursor: pointer;
outline: none;
}
a {
color: inherit;
}
img {
max-width: 100%;
height: auto;
}
body {
font: normal 16px/1.5 "Inter", sans-serif;
background: var(--columbia-blue);
color: var(--black);
margin-bottom: 50px;
}
/* .section SECTION
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.section {
padding: 50px 0;
}
.section .container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
text-align: center;
}
.section h1 {
font-size: 2.5rem;
line-height: 1.25;
}
.section h2 {
font-size: 1.3rem;
}
/* TIMELINE
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.timeline {
position: relative;
white-space: nowrap;
max-width: 1400px;
padding: 0 10px;
margin: 0 auto;
display: grid;
grid-template-columns: 320px auto;
grid-gap: 20px;
}
.timeline::before,
.timeline::after {
content: "";
position: absolute;
top: 0;
bottom: 30px;
width: 100px;
z-index: 2;
}
.timeline::after {
right: 0;
background: linear-gradient(270deg, var(--timeline-gradient));
}
.timeline::before {
left: 340px;
background: linear-gradient(90deg, var(--timeline-gradient));
}
.timeline .info {
display: flex;
flex-direction: column;
justify-content: center;
padding: 20px 40px;
color: var(--white);
background: var(--midnight-green);
white-space: normal;
border-radius: 10px;
}
.timeline .info img {
margin-bottom: 20px;
}
.timeline .info p {
margin-top: 10px;
color: var(--crystal);
}
.timeline .info a {
text-decoration: none;
}
.timeline ol::-webkit-scrollbar {
height: 12px;
}
.timeline ol::-webkit-scrollbar-thumb,
.timeline ol::-webkit-scrollbar-track {
border-radius: 92px;
}
.timeline ol::-webkit-scrollbar-thumb {
background: var(--midnight-green);
}
.timeline ol::-webkit-scrollbar-track {
background: var(--yellow);
}
.timeline ol {
font-size: 0;
padding: 250px 0;
transition: all 1s;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scrollbar-color: var(--yellow) var(--midnight-green);
}
.timeline ol li {
position: relative;
display: inline-block;
list-style-type: none;
width: 160px;
height: 5px;
background: var(--white);
scroll-snap-align: start;
}
.timeline ol li:last-child {
width: 340px;
}
.timeline ol li:not(:first-child) {
margin-left: 14px;
}
.timeline ol li:not(:last-child)::after {
content: "";
position: absolute;
top: 50%;
left: calc(100% + 1px);
bottom: 0;
width: 16px;
height: 16px;
transform: translateY(-50%);
border-radius: 50%;
background: var(--midnight-green);
z-index: 1;
}
.timeline ol li div {
position: absolute;
left: calc(100% + 7px);
width: 280px;
padding: 15px;
font-size: 1rem;
white-space: normal;
color: var(--black);
background: var(--white);
border-radius: 0 10px 10px 10px;
}
.timeline ol li div::before {
content: "";
position: absolute;
top: 100%;
left: 0;
width: 0;
height: 0;
border-style: solid;
}
.timeline ol li:nth-child(odd) div {
top: -16px;
transform: translateY(-100%);
border-radius: 10px 10px 10px 0;
}
.timeline ol li:nth-child(odd) div::before {
top: 100%;
border-width: 8px 8px 0 0;
border-color: var(--white) transparent transparent transparent;
}
.timeline ol li:nth-child(even) div {
top: calc(100% + 16px);
}
.timeline ol li:nth-child(even) div::before {
top: -8px;
border-width: 8px 0 0 8px;
border-color: transparent transparent transparent var(--white);
}
.timeline time {
display: block;
font-size: 1.4rem;
font-weight: bold;
margin-bottom: 8px;
color: var(--midnight-green);
}
/* GENERAL MEDIA QUERIES
–––––––––––––––––––––––––––––––––––––––––––––––––– */
@media screen and (max-width: 800px) {
.timeline {
display: block;
}
.timeline::before,
.timeline::after {
width: 50px;
}
.timeline::before {
left: 0;
}
.timeline .info {
display: none;
}
}
/* FOOTER STYLES
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.page-footer {
position: fixed;
right: 0;
bottom: 0;
display: flex;
align-items: center;
padding: 5px;
z-index: 2;
color: var(--black);
background: var(--columbia-blue);
}
.page-footer a {
display: flex;
margin-left: 4px;
}
// VARIABLES
const elH = document.querySelectorAll(".timeline li > div");
// START
window.addEventListener("load", init);
function init() {
setEqualHeights(elH);
}
// SET EQUAL HEIGHTS
function setEqualHeights(el) {
let counter = 0;
for (let i = 0; i < el.length; i++) {
const singleHeight = el[i].offsetHeight;
if (counter < singleHeight) {
counter = singleHeight;
}
}
for (let i = 0; i < el.length; i++) {
el[i].style.height = `${counter}px`;
}
}