اذهب إلى المحتوى

تأثيرات التمرير في صفحات الويب باستخدام Javascript وCSS– الجزء الثالث


عبد اللطيف ايمش

أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددٌ من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا.
يمكننا الاستفادة من الحدث scroll في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز.
تحدثنا في المقالتين السابقتين عن التأثيرات الآتية:

  • إخفاء صورة خلفية تدريجيًا عند التمرير
  • توضيح الصورة عند التمرير
  • تدوير العناصر عند التمرير
  • تأثير اختلاف المظهر parallax
  • إظهار صورة الخلفية عند التمرير باستخدام CSS فقط
  • تمرير سلس للصفحة
  • تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال

وسنشرح في هذه المقالة (الثالثة) طريقة إنشاء:

  • عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح
  • تأثير غروب الشمس باستخدام SVG
  • إظهار فيديو في الخلفية
  • صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript

سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير.

عنصرٌ قابلٌ للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح

1-CustomScrollingElementWithKeyboardAccessibility.jpg

(تجربة حية)
كقاعدة عامة، إخفاء المعلومات المهمة داخل عنصر قابل للتمرير هي فكرةٌ سيئة، لكنه تُستعمَل عادةً من المصممين لأنها تبدو «ذات مظهرٍ جيد» بدلًا من التفكير حول قابلية استخدامها؛ لكن هنالك حالات يمكن فيها من الضروري فعل ذلك، وعندئذٍ يجب أن تكون الروابط داخل تلك العناصر قابلةً للوصول عبر لوحة المفاتيح.

شيفرات HTML و CSS الأساسية

تقريبًا جميع العناصر يمكن أن تُضبَط لها الخاصية overflow: scroll، لذا لن يصعب علينا إنشاء شيفرة HTML. سأذكر في هذا المثال بعض الأماكن في أفريقيا:

<ol id="scrolling-list">
    <li><a href=#><img src="tunisia.jpg" alt>Tunisia</a>
    <li><a href=#><img src="botswana.jpg" alt>Botswana</a>
    <li><a href=#><img src="south-africa.jpg" alt>South Africa</a>
    <li><a href=#><img src="kenya.jpg" alt>Kenya</a>
    <li><a href=#><img src="nigeria.jpg" alt>Nigeria</a>
    <li><a href=#><img src="tanzania.jpg" alt>Tanzania</a>
</ol>

ستعرض شيفرة CSS التي سنكتبها القائمةَ بارتفاعٍ معيّن، الخاصية height نفسها لن تؤثر على طريقة العرض، فالقاعدة العامة هي أنَّ المحتوى سيُعرَض دومًا حتى لو تجاوز حدود العنصر الحاوي له. إذا أردنا أن نعكس هذا السلوك، فعلينا القيام بخطواتٍ معيّنة، وفي هذه الحالة، سنضبط الخاصية overflow-y: scroll لنتيح إمكانية التمرير داخل القائمة. لاحظ استخدامنا للكلمة المحجوزة currentcolor وغيرها من الاختصارات التي تجعل عملية التطوير أسهل.

ol#scrolling-list {
    font-size: 0;
    background: #333;
    list-style-type: none;
    padding-left: 0;
    height: 230px;
    overflow-y: scroll;
    font-weight: 100;
    color: #999;
}
ol#scrolling-list li { 
    border-bottom: 1px dashed; 
}
ol#scrolling-list li a {
    font-size: 1.2rem;
    text-decoration: none;
    line-height: 2;
    color: currentcolor;
    display: block;
    transition: .4s background;
}
ol#scrolling-list li a img {
    width: 20%;
    vertical-align: top;
    margin-right: .5rem;
}

عملية تخصيص شريط التمرير أصبحت محدودة: ففي وقتٍ سابقٍ كان متصفحا Internet Explorer و Firefox يستعملان مُحدِّدات CSS ‏(CSS selectors) لفعل ذلك، لكنهما أهملا دعمها لاحقًا. ما يزال بإمكاننا تخصيص شريط التمرير في المتصفحات التي تعتمد على المحرك Webkit، بسلسلة من المُحدِّدات الخاصية بهذا النوع من المتصفحات (والتي تُشبه تلك التي نستعملها لتخصيص حقل range للإدخال):

ol#scrolling-list::-webkit-scrollbar { 
    background: #000; 
}
ol#scrolling-list::-webkit-scrollbar-thumb {
    background-color: hsl(33,100%,50%); 
}

في النهاية، سنُخصِّص حالة ‎:hover للروابط وسنُخصِّص حالة ‎:focus أيضًا بتجميعهما معًا وذلك لتوضيح ما هو الرابط الذي نُحدِّده عبر لوحة المفاتيح:

ol#scrolling-list li a:hover,
ol#scrolling-list li a:focus { 
    background: #111; 
}

تحسين قابلية الوصول باستخدام JavaScript

بافتراض أنَّ لديك إمكانية كاملة للتنقل باستخدام لوحة المفاتيح في متصفحك (أسهل متصفح لتجربة ذلك هو Chrome، إذ تتطلب بقية المتصفحات أن تضبط بعض الخيارات أولًا) وستجد أنَّك إذا ضغطتَ على زر TAB فستنتقل بين الروابط في السلسلة، فبعد أن تصبح داخل السلسلة ستتمكن من الانتقال إلى الأمام (أي إلى الروابط التالية) باستخدام TAB أو إلى الخلف (أي إلى الروابط السابقة) باستخدام SHIFT+TAB، وتتحكم أزرار الأسهم بتمرير العنصر. لا يوجد شيءٌ خاطئٌ في ما سبق، لكن في بعض الحالات سترغب بالسماح للمستخدم باستعمال أزرار الأسهم لاختيار العناصر في القائمة بدلًا من التمرير.
سنحتاج في البداية إلى تحديد بعض الكائنات باستخدام JavaScript:

var locales = document.getElementById('scrolling-list'),
listItems = locales.children,
allLnks = new Array();
for (var i = 0;i<listItems.length;i++) {
    allLnks[i] = listItems[i].firstElementChild;
}

المتغير listItems يمثِّل العناصر المُشكِّلة للقائمة، بينما allLnks فهو مصفوفة للروابط الموجودة داخل عناصر القائمة. ولأننا وضعنا تلك العناصر داخل بعضها بعضًا فهذا سيجعل بقية السكربت معقدة قليلًا:

locales.addEventListener('keydown', function(e) {
    var focusedElement = document.activeElement,
    index = allLnks.indexOf(focusedElement);
    if (index >= 0) {
        if (e.keyCode == 40 || e.keyCode == 39) {
            if (focusedElement.parentNode.nextElementSibling) {
                var nextNode = focusedElement.parentNode.nextElementSibling.firstElementChild;
                nextNode.focus();
            } else {
                listItems[0].firstElementChild.focus(); 
            }
        }
        if (e.keyCode == 38 || e.keyCode == 37) {
            if (focusedElement.parentNode.previousElementSibling) {
                var previousNode = focusedElement.parentNode.previousElementSibling.firstElementChild;
                previousNode.focus();
            } else {
                locales.lastElementChild.firstElementChild.focus();
            }
        }
    }
});

أنشأنا دالةً لمعالجة الحدث keydown (الذي يُطلَق عندما يُضغَط على أحد الأزرار في لوحة المفاتيح) عندما يَحدُثُ داخل الكائن locales، لكننا نريد أن نُغيّر سلوك مفاتيح الأسهم إذا كان أحد عناصر القائمة مُركَّزًا عليه (focused)، وإلا فسنتحكّم بسلوك مفاتيح الأسهم من بداية تحمل الصفحة، وهذا ما سيمنع المستخدمين من التمرير في الصفحة باستخدامها.
لفعل ذلك سنتحقق من العنصر المُركَّز عليه حاليًا (عبر document.activeElement) وسنرى إن كان يُطابِق أحد عناصر مصفوفة الروابط التي أنشأناها، فإن طابق أحدها فسنتحقق إن كان الزر المضغوط مساوٍ لرمز السهم السفلي أو الأيمن، فإن كان كذلك فسيتم التحقق من وجود عنصرٍ يلي العنصرَ الحالي، فإن وجد فسيتم نقل التركيز إلى العنصر التالي، وإلا فسيتم التركيز على أوّل عنصر في القائمة.
الشيفرة الخاصة بتغيير سلوك السهم العلوي أو الأيسر مشابهة لما سبق، حيث سيُنقَل التركيز إلى العنصر الذي يسبق العنصر الحالي، وسيُنقَل التركيز إلى آخر رابط إن وصلنا إلى أعلى القائمة.

الخلاصة

إذا فكّرتَ قليلًا بالسكربت وخططت له، فيمكنك إنشاء شريط تنقل جميل وقابل للوصول، وذلك بتطبيق ما تعلمته هنا لكن مع بعض التحسينات.

تأثير غروب الشمس باستخدام SVG

2-ScrollingSVGSunset.jpg

(تجربة حية)
الرسوميات التي تصوِّر الطبيعة مناسبةٌ جدًا لتأثيرات parallax، وعادةً تتحرك عناصر تلك الرسوميات شاقوليًا، وتستخدم عددًا هائلًا من صور PNG (التي لها شفافية) كطبقات.
وخطر ببالي أنَّه يمكن توظيف رسومات SVG كبديل ممتاز لما سبق: حيث أنَّ حجم الصورة صغيرٌ جدًا، ويمكن إعادة تلوين عناصرها أو تحريكهم كلًا على حدة كما هو ظاهر في هذا المثال.

بناء الهضبات مستوية السطح

تتألف الصورة من سلسلة من الهضبات مستوية السطح التي هي مسارات مغلقة (closed paths)، باستثناء الشمس التي هي دائرة مُنشَأة بعنصر <circle>:

<svg id="arizona" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 750 279">
    <circle id="sun" fill="#FFF7EB" cx="655" cy="128" r="41.5"/>
    <path fill="hsl(32, 89%, 75%)" d="M750 ... "/>
    <path fill="hsl(31, 74%, 71%)" d="M745 ..." />

أنشأنا المسارات البعيدة أولًا، أي أنَّ أبعد هضبة ستُعرَّف في البداية، ثم تليها الأقرب فالأقرب.

السماء والتدرجات

بدلًا من إنشاء عنصر <rect> للسماء، فسيتم ملء خلفية عنصر <svg> باستخدام CSS:

#arizona { 
    background: hsl(47, 100%, 86%);
}

استخدام ألوان HSL (سواءً داخل شيفرات SVG أو عبر أنماط CSS) هو المفتاح الرئيسي لهذا التأثير، وذلك بتغير درجة السطوع (luminosity) لكل عنصر وذلك عند التمرير، وبذلك سنعطي انطباعًا بشروق أو غروب الشمس.
الجزء الصعب هو استخراج قيمة HSL لكل عنصر، ولفعل ذلك سأستخدم التعابير النمطية (regular expressions) في JavaScript، هذه الشيفرة تُعرِّف التعبير النمطي الذي سنستخدمه مع جمع بعض المعلومات عن عنصر SVG:

var regex = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/,
arizona = document.getElementById("arizona"),
mesaLayers = arizona.querySelectorAll("path"),
SVGoffsettop = arizona.getBoundingClientRect().top,
vertHeight = arizona.getBoundingClientRect().height,
sun = document.getElementById("sun");

المتغير mesaLayers يضم جميع العناصر المُشكِّلة للهضبات معًا، وسيتم التعامل مع التمرير داخل دالة:

function scrollHandler() {
    if (window.scrollY < vertHeight) {
        Array.prototype.forEach.call(mesaLayers, function(layer) { 
        var layerFill = layer.getAttribute("fill"),
        vertRoll = Math.abs(window.scrollY - vertHeight) / vertHeight;
        hslComponents = layerFill.match(regex).slice(1),
        newLum = parseFloat(hslComponents[2]) * vertRoll;
        layer.style.fill = "hsl(" + hslComponents[0] +", " + hslComponents[1] + "%, " +  newLum + "%)";
        arizona.style.background = "hsl(48, " + 100 * vertRoll + "%, " + 88 * vertRoll + "%)";
        sun.style.transform = "translate3d(0," + window.scrollY / 10 + "px, 0)";
    })
}

هذه الدالة تفعل ما يلي بالترتيب:

  1. الحصول على الخاصية fill لكل عنصر path
  2. تحديد مدى تمرير النافذة
  3. استخلاص قيمة HSL من كل عنصر path
  4. تعديل سطوع العنصر اعتمادًا على مقدار التمرير
  5. إعادة تجميع لون HSL لكل عنصر path الذي يضم السطوع الجديد، وتطبيقه على كل عنصر
  6. تعديل خاصية background لعنصر SVG، وأيضًا اعتمادًا على مقدار التمرير
  7. تمرير عنصر sun إلى الأسفل باستخدام translate3d لإنشاء تأثير الغروب

ملاحظة: لا تعمل ميزة CSS transforms على عناصر SVG في متصفح Internet Explorer أو Edge بعد، على الرغم من أنَّ مفترض أن تدعم الإصدارات القادمة تلك الميزة.
تُستدعى الدالة باستخدام requestAnimationFrame لتحسين الأداء:

window.onscroll = function() {
    window.requestAnimationFrame(scrollHandler);
}

تبطيء التأثير

قد تواجه إشكاليات عند ربط العناصر بالتمرير، فقد تتحول العناصر بسرعة كبيرة مما يجعلك تفقد شعورك بالتأثير… لذا فإنَّ أسهل طريقة لتبطيء التأثير هي استخدام مقياس للتمرير. غيّر الشيفرة السابقة لتصبح كما يلي:

if (window.scrollY < SVGoffsettop * 4) {
      Array.prototype.forEach.call(mesaLayers, function(layer) { 
          var layerFill = layer.getAttribute("fill"),
          vertRoll = Math.abs((window.scrollY / 4 ) - SVGoffsettop) / SVGoffsettop;

الخلاصة وأمور يمكن تحسينها

عادةً يُستعمَل هذا التأثير بعد ضبط الخاصية position: fixed على عنصر SVG لإبقائه ظاهرًا أثناء تمرير الصفحة، إلا أنني لم أفعل ذلك هنا لأغراضٍ توضيحية. يمكن أيضًا دمج تأثير parallax معه عند التمرير، لكنني قررتُ أن أركِّز على تأثير غروب الشمس فقط.
هنالك جانبان يمكن تطويرهما في السكربت:

  1. تكرار استخراج قيم ألوان HSL وتركيبها، فمن الأفضل جعل تلك القيم كخاصيات لكل عنصر لكي يتم الوصول إليها بسهولة عبر السكربت، بدلًا من إعادة حسابها كل مرة.
  2. ألوان خلفية السماء مكتوبة ضمن السكربت؛ ومن الأفضل إسناد الألوان باستخدام CSS، مما يجعل السكربت قادرًا على التعامل مع التغييرات في العرض دون الحاجة إلى تكرار التغييرات.

إظهار فيديو في الخلفية

3-LayeredScrollingVideowithBlendModes.jpg

(تجربة حية)
نُشِرَت مقالة عن كيفية إنشاء فيديو في كامل خلفية الصفحة باستخدام HTML5 ، لكن أتت أسئلة على ذاك المقال للسؤال عن كيفية إنشاء فيديو يظهر خلف المحتوى، لكن يمكن تمريره كباقي محتويات الصفحة.
فاجأني ذلك قليلًا، لأنَّ بالإمكان فعل ذلك باستخدام CSS مع نفس التقنيات التي نستعملها مع الصور… لكن أتتني الفرصة هنا لإعطاء مثال عن أنماط الاندماج (blend modes).

الشيفرات

تبدو شيفرة إضافة مقطع الفيديو تقليديةً، حيث سنضعها داخل وسم <main> (بدلًا من وضعها مباشرةً بعد العنصر <body> كما في المقالة الأصلية)، وسأفترض في هذا المثال أنَّ وسم video موجودٌ داخل العنصر <header> ضمن وسم <main>:

<main>
  <header>
    <video autoplay loop>
      <source src="forest-fire.webm">
      <source src="forest-fire.mp4">
    </video>
  </header>

ملاحظة: يجب أن يتبع الفيديو نفس القواعد العامة لمقاطع الفيديو التي تعمل في الخلفية الموجودة في المقالة الأصلية.
يجب تنسيق الفيديو بأنماط CSS مماثلة لتلك التي كنتَ ستستعملها لعرض الصور المتجاوبة بكامل العرض:

main { 
  width: 80%;
  max-width: 750px;
  margin: 0 auto;
}
main > header video {
  width: 100%;
  height: auto;
}

ملاحظة: إذا أردتَ أن يظهر الفيديو بكامل عرض الشاشة، فبدِّل قيمة الخاصيتين width و max-width للعنصر main لتوسعته.
يجب إضافة «طبقة» أمام مقطع الفيديو فيها ترويسة ورابط للانتقال إلى محتوى الصفحة. العناصر التالية يجب أن توضع بعد الوسم <video>:

   <h1>A world Aflame</h1>
   <a href="#maincontent"></a>
</header>

سيؤدي الضغط على الرابط إلى الانتقال إلى العنصر ذي المعرِّف maincontent. يجب أن نُعدِّل CSS الآن للسماح بإظهار العناصر الجديدة كطبقة تعلو مقطع الفيديو:

main > header { 
  position: relative;
}

أنماط CSS للترويسة <h1> وللرابط:

main > header h1 {
  position: absolute;
  bottom: 40%;
  left: 1rem;
  font-size: 4rem;
  text-transform: uppercase;
  mix-blend-mode: overlay;
}
main > header a {
  display: block;
  text-decoration: none;
  font-size: 2rem;
  color: #fff;
  opacity: .5;
  position: absolute;
  bottom: 1.5rem;
  width: 100%;
  text-align: center;
  transition: .3s;
  animation: downwardprompt 2s 1s;
}
main > header a:hover {
  opacity: 1;
}

سيتم تطبيق تأثير حركي على السهم بعد عدِّة ثواني من تحميل الصفحة، مما يلفت انتباه المستخدم إليه:

@keyframes downwardprompt {
  to { 
    transform: translateY(2rem);
    opacity: 0;
    }
}

هذا كل ما في الأمر، بالطبع يمكنك القيام بالكثير باستخدام هذه التقنية، إلا أنَّ شيفرات CSS الأساسية ستبقى نفسها تقريبًا.

صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript

4-ParallaxImageScrollingAnimationCSS3D.jpg

(تجربة حية)
صحيحٌ أنَّ هنالك الكثير من الطرائق والتقنيات الموجودة على الويب لإنشاء تأثير parallax، لكنني أرى أنَّها تُزِّيف تأثير العمق في الصور، لكنني وجدتُ أنَّ تقنيةCSS 3D تسمح بتغيير مكان الصور على المحور z، مما يجعل تأثير تغيير المنظور حقيقيًا أثناء تحريك الصور إلى الأعلى وإلى الأسفل. وصحيحٌ أنَّ شيفرة هذا المثال ما تزال بدائيةً وبسيطةً، إلا أنَّني أرى أنها تستحق المشاركة.

الشيفرات الأساسية

هنالك شيفرة HTML بسيطة جدًا في هذا المثال، وهي عبارة عن عنصر <div> بسيط:

<div id="parallax-container">
</div>

سيُملأ هذا العنصر بالصور المُحمَّلة عبر شيفرة JavaScript، لكن علينا أولًا أن نضبط الأنماط اللازمة لعنصر <div> وللصور التي ستظهر داخله:

#parallax-container {
    background: #16161d;
    margin: 0;
    overflow: hidden;
    perspective: 1200px;
    height: 100vh;
    width: 100vw;
    transform-style: preserve-3d;
}
#parallax-container img {
    transform-origin: center;
    box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.4);
    position: relative;
}

ملاحظة: إن لم تكن تألف التعامل مع واحدات vw و vh أو CSS 3D، فاقرأ المزيد عنها في هذه السلاسل.

الصور المتحركة

الخطوة التالية هي إضافة الصور، وتنسيقها باستخدام CSS، ثم جعل JavaScript تخفيها ثم تُجري عمليات عليها لتحقيق التأثير المطلوب. ولأنَّ أسماء ملفات الصور لها نفس النمط في هذا المثال (أي wave1.jpg و wave2.jpg …إلخ.) فيمكنني استخدام JavaScript لتوليد أسماء الملفات مع إنشاء بعض المتغيرات التي ستلزمنا لاحقًا في السكربت:

var container = document.getElementById("parallax-container"),
waveSrc = [],
waves = [],
imgLoc = "",
j = 0;

for (var i = 0; i < 10; i++) {
    waveSrc[i] = imgLoc+"wave"+(i+1)+".jpg";
}

سنحتاج أيضًا إلى بعض الأرقام العشوائية، لذا سأولدها باستخدام هذه الدالة:

function getRandomInRange(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

سنحتاج أيضًا إلى مرجع (reference) إلى الصور التي جرى تحميلها، بالإضافة إلى عرض وارتفاع الشاشة الحالي (بافتراض أنَّ نافذة المتصفح مُكبَّرَة).

var screenWidth = window.screen.width,
screenHeight = window.screen.height;

وعند اكتمال تحميل الصور وإضافتها إلى عنصر <div>، فسنوفِّر لها خاصيات –وهي ‎.xPlane و ‎.yPlane و ‎.zPlane– بقيمٍ عشوائية، والتي ستُحدِّد موضع الصورة في فضاءٍ ثلاثي الأبعاد. سأترك قيم الخاصية alt في هذا المثال فارغةً وذلك للاختصار:

function preloadImage(filename){
    var img=new Image();
    img.onload = function(){ 
        img.xPlane = getRandomInRange(-500, screenWidth - 500);
        img.yPlane = getRandomInRange(500, 1000);
        img.zPlane = getRandomInRange(300,2000);
        img.style = "transform: translate3d(" + img.xPlane +"px, " + 
            img.yPlane + "px, -" + img.zPlane +"px)";
       container.appendChild(img);
    };
    imgLoc = "";
    img.src= imgLoc + filename;
    img.alt = "";
    waves[j] = img;
    j++;
}

function loadImages(){
    for (var i = 0; i < waveSrc.length; ++i) {
        var filename = waveSrc[i];
        preloadImage(filename);
    }
}

أخيرًا، ستُحرَّك الصور باستخدام دالة:

function moveImages(){
    waves.forEach(function(image) {
            image.yPlane = image.yPlane - 2;
            image.style.cssText = "transform: translate3d(" + image.xPlane+"px, 
" + image.yPlane+"px,  -" + image.zPlane + "px); z-index: " + image.zIndex;
        });
    window.requestAnimationFrame(moveImages);
}

وسيتم تشغيل المثال باستدعاء الدوال المناسبة في نهاية السكربت:

loadImages();
window.addEventListener("load", 
    function() { 
        window.requestAnimationFrame(moveImages);
    });

تحسينات إضافية على المثال

ما يزال هذا المثال مبدئيًا، وهنالك عدِّة أشياء يمكن إجراؤها لتطويره:
1. سيستمر تشغيل السكربت حتى بعد أن تختفي الصور من أعلى العنصر الحاوي لها، وستستمر بالحركة إلى اللانهاية؛ لذا من الأفضل أنَّ نُزيل الصور من بداية المصفوفة بعد اختفائها ثم إضافتها مرةً أخرى لتظهر مجددًا.
2. ربما من الأفضل أنَّ نُقلِّل من العشوائية في مواضع الصور، فالآن يمكن أن تظهر إحدى الصور خلف صورةٍ أخرى مباشرةً، أو قريبة منها كثيرًا في البُعد z (وبالتالي ستتحرك الصورتان بسرعةٍ قريبةٍ من بعضهما). ولفعل ذلك علينا أن نقارن أماكن الصور الجديدة بتلك التي أنشأناها من قبل في المصفوفة، وتوليد قيمة جديدة إن كانت القيمتان متقاربتين.
3. سيتم تحريك الصور تلقائيًا، إذا أردتَ أن تربط حركة الصور بتغيير شريط التمرير في الصفحة، فعليك أن تُغيّر موضع الصور بالنسبة إلى window.scrollY.

ترجمة وبتصرّف للمقالات A Custom Scrolling Element With Keyboard Accessibility و Scrolling Background Video with Layered Content و A Scrolling SVG Sunset و Parallax Image Scrolling Animation with CSS 3D and JavaScript لصاحبها Dudley Storey


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...