下面我将为你提供几种从简单到复杂的实现方法,包括纯 CSS、结合少量 JavaScript 的现代方案,以及一个功能更丰富的专业级图片查看器。

网页特效 点击图片放大
(图片来源网络,侵删)

纯 CSS 方案(简单、快速)

这种方法利用 CSS 的 target 伪类,无需任何 JavaScript,当用户点击图片时,它会链接到一个锚点(),然后通过 CSS 将图片放大并居中显示。

实现步骤:

  1. HTML 结构

    • 每张图片用一个 <a> 标签包裹,href 指向一个唯一的 ID(#img1)。
    • 放大后的图片是一个隐藏的 <div>,它的 ID 与上面 <a> 标签的 href 对应。
    • 在这个 <div> 内部,放置一张 <img>,并添加一个关闭按钮。
    <style>
      /* 基础样式 */
      .gallery img {
        width: 200px;
        height: 150px;
        object-fit: cover;
        cursor: pointer;
        transition: transform 0.3s ease;
      }
      .gallery img:hover {
        transform: scale(1.05);
      }
      /* 默认隐藏放大后的图片容器 */
      .lightbox {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.9);
        z-index: 1000;
        text-align: center;
      }
      /* 当链接被点击后(:target),显示放大图片 */
      .lightbox:target {
        display: flex;
        justify-content: center;
        align-items: center;
      }
      /* 放大后的图片样式 */
      .lightbox img {
        max-width: 90%;
        max-height: 90%;
        object-fit: contain;
      }
      /* 关闭按钮样式 */
      .close {
        position: absolute;
        top: 20px;
        right: 35px;
        color: #f1f1f1;
        font-size: 40px;
        font-weight: bold;
        cursor: pointer;
      }
      .close:hover {
        color: #bbb;
      }
    </style>
    <div class="gallery">
      <a href="#img1">
        <img src="https://via.placeholder.com/200x150?text=Image+1" alt="图片1">
      </a>
      <a href="#img2">
        <img src="https://via.placeholder.com/200x150?text=Image+2" alt="图片2">
      </a>
      <!-- 更多图片... -->
    </div>
    <!-- 放大后的图片容器 -->
    <div id="img1" class="lightbox">
      <span class="close">&times;</span>
      <img src="https://via.placeholder.com/800x600?text=Image+1+Large" alt="放大图片1">
    </div>
    <div id="img2" class="lightbox">
      <span class="close">&times;</span>
      <img src="https://via.placeholder.com/800x600?text=Image+2+Large" alt="放大图片2">
    </div>

优缺点:

  • 优点:代码简单,无需 JS,性能好。
  • 缺点
    • URL 会变得奇怪(页面后缀会加上 #img1)。
    • 如果图片很多,HTML 会变得很冗余。
    • 功能有限,无法实现平滑的淡入淡出动画(除非配合 JS)。

JavaScript + CSS 方案(灵活、推荐)

这是目前最主流和灵活的方法,通过 JS 控制一个模态框(Modal)的显示和隐藏,可以实现更丰富的交互效果,如平滑动画、键盘关闭等。

实现步骤:

  1. HTML 结构

    网页特效 点击图片放大
    (图片来源网络,侵删)
    • 图片列表。
    • 一个隐藏的模态框容器,里面包含放大的图片和关闭按钮。
    <style>
      /* 图片列表样式 */
      .gallery img {
        width: 200px;
        height: 150px;
        object-fit: cover;
        cursor: pointer;
        margin: 5px;
        transition: transform 0.3s ease;
      }
      .gallery img:hover {
        transform: scale(1.05);
      }
      /* 模态框基础样式 */
      .modal {
        display: none; /* 默认隐藏 */
        position: fixed;
        z-index: 1000;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        overflow: auto;
        background-color: rgba(0, 0, 0, 0.9);
        opacity: 0; /* 初始透明 */
        transition: opacity 0.3s ease; /* 淡入效果 */
      }
      /* 模态框内容 */
      .modal-content {
        display: block;
        margin: auto;
        max-width: 80%;
        max-height: 80%;
        animation: zoom 0.3s ease; /* 缩放动画 */
      }
      /* 关闭按钮 */
      .close {
        position: absolute;
        top: 15px;
        right: 35px;
        color: #f1f1f1;
        font-size: 40px;
        font-weight: bold;
        cursor: pointer;
        transition: color 0.3s ease;
      }
      .close:hover {
        color: #bbb;
      }
      /* 动画效果 */
      @keyframes zoom {
        from { transform: scale(0.5); }
        to { transform: scale(1); }
      }
    </style>
    <div class="gallery">
      <img src="https://picsum.photos/200/150?random=1" alt="图片1" onclick="openModal(this)">
      <img src="https://picsum.photos/200/150?random=2" alt="图片2" onclick="openModal(this)">
      <img src="https://picsum.photos/200/150?random=3" alt="图片3" onclick="openModal(this)">
    </div>
    <!-- 模态框 -->
    <div id="imageModal" class="modal">
      <span class="close" onclick="closeModal()">&times;</span>
      <img class="modal-content" id="modalImg">
    </div>
  2. JavaScript 代码

    • openModal() 函数:获取被点击图片的 src,将其赋值给模态框内的 <img>,然后显示模态框。
    • closeModal() 函数:隐藏模态框。
    function openModal(img) {
      // 获取模态框和其中的图片元素
      const modal = document.getElementById("imageModal");
      const modalImg = document.getElementById("modalImg");
      // 设置模态框内图片的源为被点击图片的源
      modalImg.src = img.src;
      // 显示模态框
      modal.style.display = "block";
      // 淡入效果
      setTimeout(() => {
        modal.style.opacity = "1";
      }, 10);
    }
    function closeModal() {
      const modal = document.getElementById("imageModal");
      // 淡出效果
      modal.style.opacity = "0";
      // 等待淡出动画完成后,再隐藏元素
      setTimeout(() => {
        modal.style.display = "none";
      }, 300);
    }
    // 点击模态框的背景部分也可以关闭
    window.onclick = function(event) {
      const modal = document.getElementById("imageModal");
      if (event.target == modal) {
        closeModal();
      }
    }
    // 按下 ESC 键关闭模态框
    document.addEventListener('keydown', function(event) {
      if (event.key === 'Escape') {
        closeModal();
      }
    });

优缺点:

  • 优点:功能强大,交互流畅,URL 保持干净,代码结构清晰,可扩展性强。
  • 缺点:需要编写少量 JavaScript 代码。

使用专业库(功能强大、省心)

如果你不希望自己编写代码,可以直接使用现成的图片查看器库,它们提供了非常丰富的功能,如全屏、缩放、旋转、播放幻灯片等。

推荐库:PhotoSwipe

PhotoSwipe 是一个功能强大、移动端友好的开源图片库。

实现步骤:

  1. 引入 CSS 和 JS 文件

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.4.2/photoswipe.min.css" integrity="sha512-yJ+y8v4ylVjN/JdMl0YkV6gHKd3boLd7PpA/PF8ruFmW3/AlU6Ll+Vj5D6n8yfNUZ6xL7s6+V6yU1v3b5c3Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.4.2/default-skin/default-skin.min.css" integrity="sha512-A9eOZ5nKk7lB3j8PuzL8iGq7t6zXnZ5oqH4n6l7b5u1g8s3a6wGz5b5w6jz5b5u1g8s3a6wGz5b5w6jz5b5u1g8s3A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.4.2/photoswipe.min.js" integrity="sha512-6sJHn2XTHiZJi6w9Tg3Zo/NfSgejQgOj8tXz5gKzUWVw5k7k+Y4y5L5i5k5y5L5i5k5y5L5i5k5y5L5i5k5y5A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.4.2/photoswipe-ui-default.min.js" integrity="sha512-5s3n4r3L4LhJ2qz8X5j3K8eQH7f5J6y4X5k5y5L5i5k5y5L5i5k5y5L5i5k5y5L5i5k5y5L5i5k5y5L5i5k5y5A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  2. 准备 HTML 结构

    • .pswp__bg 是背景。
    • .pswp__scroll-wrap 是滚动容器。
    • .pswp__container 是图片容器。
    • .pswp__item 是每张图片的容器。
    • <a> 标签中放置 <img>,并添加 data-pswp-widthdata-pswp-height 属性。
    <!-- Root element of PhotoSwipe -->
    <div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
      <div class="pswp__bg"></div>
      <div class="pswp__scroll-wrap">
        <div class="pswp__container">
          <div class="pswp__item"></div>
          <div class="pswp__item"></div>
          <div class="pswp__item"></div>
        </div>
        <div class="pswp__ui pswp__ui--hidden">
          <!-- ... UI Controls ... -->
        </div>
      </div>
    </div>
    <!-- 你的图片列表 -->
    <div class="my-gallery" itemscope itemtype="http://schema.org/ImageGallery">
      <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
        <a href="https://picsum.photos/1200/800?random=1" itemprop="contentUrl" data-size="1200x800">
          <img src="https://picsum.photos/200/150?random=1" itemprop="thumbnail" alt="图片1">
        </a>
      </figure>
      <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
        <a href="https://picsum.photos/1200/800?random=2" itemprop="contentUrl" data-size="1200x800">
          <img src="https://picsum.photos/200/150?random=2" itemprop="thumbnail" alt="图片2">
        </a>
      </figure>
      <!-- 更多图片... -->
    </div>
  3. 初始化 PhotoSwipe

    document.addEventListener('DOMContentLoaded', function () {
      var initPhotoSwipeFromDOM = function(gallerySelector) {
        var gallery = document.querySelector(gallerySelector);
        var parseThumbnailElements = function(el) {
          var thumbElements = el.childNodes,
              numNodes = thumbElements.length,
              items = [],
              figureEl,
            linkEl,
            size,
            item;
          for(var i = 0; i < numNodes; i++) {
            figureEl = thumbElements[i]; // <figure> element
            if(figureEl.nodeType !== 1) {
              continue;
            }
            linkEl = figureEl.children[0]; // <a> element
            size = linkEl.getAttribute('data-size').split('x');
            // create slide object
            item = {
              src: linkEl.getAttribute('href'),
              w: parseInt(size[0], 10),
              h: parseInt(size[1], 10),
              author: linkEl.getAttribute('data-author')
            };
            if(figureEl.children.length > 1) {
              // <figcaption> content
              item.title = figureEl.children[1].innerHTML;
            }
            if(linkEl.children.length > 0) {
              // <img> thumbnail element, retrieving thumbnail url
              item.msrc = linkEl.children[0].getAttribute('src');
            }
            item.el = figureEl; // save link to element for getThumbBoundsFn
            items.push(item);
          }
          return items;
        };
        var closest = function closest(el, fn) {
          return el && ( fn(el) ? el : closest(el.parentNode, fn) );
        };
        var onThumbnailsClick = function(e) {
          e = e || window.event;
          e.preventDefault ? e.preventDefault() : e.returnValue = false;
          var eTarget = e.target || e.srcElement;
          var clickedListItem = closest(eTarget, function(el) {
            return (el.tagName && el.tagName.toUpperCase() === 'FIGURE');
          });
          if(!clickedListItem) {
            return;
          }
          var clickedGallery = clickedListItem.parentNode,
              childNodes = clickedListItem.parentNode.childNodes,
              numChildNodes = childNodes.length,
              nodeIndex = 0,
              index;
          for (var i = 0; i < numChildNodes; i++) {
            if(childNodes[i].nodeType !== 1) { 
              continue; 
            }
            if(childNodes[i] === clickedListItem) {
              index = nodeIndex;
              break;
            }
            nodeIndex++;
          }
          if(index >= 0) {
            openPhotoSwipe( index, clickedGallery );
          }
          return false;
        };
        var photoswipeParseHash = function() {
          var hash = window.location.hash.substring(1),
              params = {};
          if(hash.length < 5) { // pid=1
            return params;
          }
          var vars = hash.split('&');
          for (var i = 0; i < vars.length; i++) {
            if(!vars[i]) {
              continue;
            }
            var pair = vars[i].split('=');  
            if(pair.length < 2) {
              continue;
            }           
            params[pair[0]] = pair[1];
          }
          if(params.gid) {
            params.gid = parseInt(params.gid, 10);
          }
          return params;
        };
        var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromThumb) {
          var pswpElement = document.querySelectorAll('.pswp')[0],
              gallery,
              options,
              items;
          items = parseThumbnailElements(galleryElement);
          // define options (if needed)
          options = {
            galleryUID: galleryElement.getAttribute('data-pswp-uid'),
            getThumbBoundsFn: function(index) {
              // See Options -> getThumbBoundsFn section of documentation for more info
              var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
                  pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
                  rect = thumbnail.getBoundingClientRect();
              return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
            }
          };
          if(disableAnimation) {
            options.showAnimationDuration = 0;
          }
          if(fromThumb) {
            options.animateZoom = false;
          }
          if(options.galleryUID) {
            options.history = false;
          }
          // Pass data to PhotoSwipe and initialize it
          gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
          gallery.init();
        };
        // loop through all gallery elements and bind events
        var galleryElements = document.querySelectorAll( gallerySelector );
        for(var i = 0, l = galleryElements.length; i < l; i++) {
          galleryElements[i].setAttribute('data-pswp-uid', i+1);
          galleryElements[i].onclick = onThumbnailsClick;
        }
        // Parse URL and open gallery if it contains #&gid=3&pid=45
        var hashData = photoswipeParseHash();
        if(hashData.pid && hashData.gid) {
          openPhotoSwipe( hashData.pid ,  galleryElements[ hashData.gid - 1 ], true, true );
        }
      };
      // initialize PhotoSwipe
      initPhotoSwipeFromDOM('.my-gallery');
    });

优缺点:

  • 优点:功能极其丰富(全屏、缩放、旋转、幻灯片、键盘/手势支持),跨浏览器兼容性好,移动端体验极佳。
  • 缺点:引入了外部库,会增加页面体积,需要遵循其特定的 HTML 结构。

总结与选择建议

方法 实现难度 功能丰富度 适用场景
纯 CSS 非常低 基础 快速实现、少量图片、对 URL 有洁癖、不想用 JS 的场景。
JS + CSS 丰富 强烈推荐,大多数网页应用的理想选择,平衡了功能、性能和开发成本。
专业库 极其丰富 专业图片画廊、作品集、电商网站等对图片查看体验要求极高的场景。

对于大多数开发者来说,方法二(JavaScript + CSS) 是最佳选择,它提供了足够的灵活性,可以轻松定制以适应各种需求,同时保持了代码的简洁和可控性。