微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 CSS 在图像周围环绕文本并使其表现得像背景图像

如何解决使用 CSS 在图像周围环绕文本并使其表现得像背景图像

我正在使用 shape-outside 为网站提供一种“杂志”的感觉。每个页面都有一个人的新图像,文字环绕着那个人。外部造型完美而简单!唯一的问题是我不知道如何制作它,因此一列(左)中的文本设置高度而不是图像(右)。

以这个例子为例:

https://jsfiddle.net/kvzmw0sy/22/

或者原始代码

HTML:

<div class="container">
  <img class="image" src="https://res.cloudinary.com/dq6tqnvbh/image/upload/v1552834755/5a366dd97df550.5130252915135165055159.png">
  <div class="text">
  Lorem ipsum dolor sit amet,consectetur adipiscing elit. Integer vestibulum rhoncus orci nec iaculis. Cras tempor aliquam sem,id accumsan nibh mollis nec. Sed eget dui pulvinar,iaculis nibh vitae,molestie metus. Aliquam tortor leo,laoreet a felis quis,ultricies dignissim mauris. Etiam quis consectetur nibh. In soDales et ex at malesuada. Phasellus et arcu eleifend,interdum ex eu,bibendum magna. 
  </div>
</div>
<div class="footer">

</div>

CSS:

.image {
  float: right;
  max-width: 200px;
  height: auto;
  shape-outside: url(https://res.cloudinary.com/dq6tqnvbh/image/upload/v1552834755/5a366dd97df550.5130252915135165055159.png);

}
.footer {
  width:100%;
  height:50px;
  border: 2px solid green
}

我得到的是这个:

enter image description here

但是,我想要的是这个(看看图像如何在页脚后面):

enter image description here

基本上我希望它像背景图像一样工作。

我尝试了绝对位置,但它破坏了文本换行。我不认为我可以用背景图片来做到这一点。所以到目前为止我唯一的解决方案是使用 JS 获取左侧的高度并将其应用到带有 overflow:hidden 的容器中,我真的很想避免这种情况。

解决方法

应用于容器的新 overflow:clip 将完成这项工作

import SwiftUI
import CoreData

extension User{
    //You need a variable you can access with your section "title" or "name"
    //This defines what you want to find in common
    @objc
    var firstLetterLastName: String{
        lastName?.first?.description ?? ""
    }
}
class UserListViewModel: NSObject,ObservableObject {
    //This uses the PersistenceController from the standard Xcode setup
    let persistenceController = PersistenceController.previewAware()
    //This contains your sections and objects/values
    @Published var fetchedResultsController: NSFetchedResultsController<User>?
    
    override init() {
        super.init()
        setupController()
    }
    func setupController() {
        do{
            //sectionNameKeyPath is where you tell the controller where to find the variable that you want to group
            fetchedResultsController = try retrieveFetchedController(sortDescriptors: nil,predicate: nil,sectionNameKeyPath: #keyPath(User.firstLetterLastName))
        }catch{
            print(error)
        }
    }
    //I put this here so sample a delete. It works a little different
    func deleteObject(object: User) {
        persistenceController.container.viewContext.delete(object)
        save()
    }
    func addSample()  {
        let newUser = User(context: persistenceController.container.viewContext)
        newUser.firstName  = ["Peter","Emily","Grace","Ruby","Chloe","James"].randomElement()!
        newUser.lastName  = ["Smith","Hughes","Scott","Brown","Turner","Simpson","Blue"].randomElement()!
        save()
    }
    func save() {
        do {
            if persistenceController.container.viewContext.hasChanges{
                try persistenceController.container.viewContext.save()
            }else{
            }
        } catch {
            print(error)
        }
    }
}
//Most of the extensions mostly comes from the CoreData Programming Guide
//https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html#//apple_ref/doc/uid/TP40001075-CH8-SW1
extension UserListViewModel: NSFetchedResultsControllerDelegate{
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        fetchedResultsController = fetchedResultsController
    }
}

//MARK: FetchedResultsController setup
extension UserListViewModel{
    func retrieveFetchedController(sortDescriptors: [NSSortDescriptor]?,predicate: NSPredicate?,sectionNameKeyPath: String) throws -> NSFetchedResultsController<User> {
        
        return try initFetchedResultsController(sortDescriptors: sortDescriptors,predicate: predicate,sectionNameKeyPath: sectionNameKeyPath)
    }
    private func initFetchedResultsController(sortDescriptors: [NSSortDescriptor]?,sectionNameKeyPath: String) throws -> NSFetchedResultsController<User> {
        fetchedResultsController = getFetchedResultsController(sortDescriptors: sortDescriptors,sectionNameKeyPath: sectionNameKeyPath)
        fetchedResultsController!.delegate = self
        do {
            try fetchedResultsController!.performFetch()
            return fetchedResultsController!
            
        } catch {
            print( error)
            throw error
        }
    }
    func getFetchedResultsController(sortDescriptors: [NSSortDescriptor]?,sectionNameKeyPath: String) -> NSFetchedResultsController<User> {
        
        return NSFetchedResultsController(fetchRequest: getEntityFetchRequest(sortDescriptors: sortDescriptors,predicate: predicate),managedObjectContext: persistenceController.container.viewContext,sectionNameKeyPath: sectionNameKeyPath,cacheName: nil)
    }
    private func getEntityFetchRequest(sortDescriptors: [NSSortDescriptor]?,predicate: NSPredicate?) -> NSFetchRequest<User>
    {
        
        let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
        fetchRequest.includesPendingChanges = false
        //This part helps with efficiency.
        //Maybe a little lazy loading SwiftUI does not slow down
        //as much with large data sets when I use this setup
        fetchRequest.fetchBatchSize = 20
        if sortDescriptors != nil{
            fetchRequest.sortDescriptors = sortDescriptors
        }else{
            fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(User.lastName),ascending: true)]
        }
        if predicate != nil{
            fetchRequest.predicate = predicate
        }
        return fetchRequest
    }
}
//Here is a sample View
struct UserListView: View {
    @StateObject var vm: UserListViewModel = UserListViewModel()
    var body: some View {
        NavigationView{
        if vm.fetchedResultsController?.sections != nil{
            List{
                ForEach(vm.fetchedResultsController!.sections!.indices){idx in
                    let section = vm.fetchedResultsController!.sections![idx]
                    UserListSectionView(objects: section.objects as? [User] ?? [],sectionName: section.name).environmentObject(vm)
                }
            }.toolbar(content: {
                ToolbarItem(placement: .navigation,content: {
                    Button(action: {
                        vm.addSample()
                    },label: {
                        Image(systemName: "plus")
                    })
                })
            })
            
        }else{
            Image(systemName: "empty")
        }
        }
    }
}


struct UserListSectionView: View {
    @EnvironmentObject var vm: UserListViewModel
    let objects: [User]
    var sectionName: String
    
    var body: some View {
        Section(header: Text(sectionName),content: {
            ForEach(objects,id: \.self){obj in
                let user = obj as User
                HStack{
                    Text(user.firstName.bound)
                    Text(user.lastName.bound)
                }
                .listRowBackground(Color(UIColor.systemBackground))
                
                
            }.onDelete(perform: deleteItems)
        })
        
    }
    //Here is the difference with deleting.
    //The IndexSet is for the section.objects not all the users
    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            
            let objs = offsets.map { objects[$0] }
            
            for obj in objs{
                
                vm.deleteObject(object: obj)
            }
        }
    }
}
struct UserListView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView{
            UserListView()
        }
    }
}
.image {
  float: right;
  max-width: 200px;
  height: auto;
  shape-outside: url(https://res.cloudinary.com/dq6tqnvbh/image/upload/v1552834755/5a366dd97df550.5130252915135165055159.png);
}

.footer {
  width: 100%;
  height: 50px;
  border: 2px solid green
}


/* .text{ 
shape-outside: url(https://www.pngjoy.com/pngl/69/1501951_stars-star-images-birthday-png-hd-png-download.png);
  } */

.container {
  overflow: clip;
}

为了获得更好的支持,您可以改用剪辑路径:

<div class="container">
  <img class="image" src="https://res.cloudinary.com/dq6tqnvbh/image/upload/v1552834755/5a366dd97df550.5130252915135165055159.png">
  <div class="text">
    Lorem ipsum dolor sit amet,consectetur adipiscing elit. Integer vestibulum rhoncus orci nec iaculis. Cras tempor aliquam sem,id accumsan nibh mollis nec. Sed eget dui pulvinar,iaculis nibh vitae,molestie metus. Aliquam tortor leo,laoreet a felis
    quis,ultricies dignissim mauris. Etiam quis consectetur nibh. In sodales et ex at malesuada. Phasellus et arcu eleifend,interdum ex eu,bibendum magna.
  </div>
</div>
<div class="footer">

</div>
.image {
  float: right;
  max-width: 200px;
  height: auto;
  shape-outside: url(https://res.cloudinary.com/dq6tqnvbh/image/upload/v1552834755/5a366dd97df550.5130252915135165055159.png);
}

.footer {
  width: 100%;
  height: 50px;
  border: 2px solid green
}


.container {
  clip-path: inset(0);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。